rea-agents 5.0.0 → 6.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 +157 -650
- package/bridge/mitmproxy/capture.py +210 -0
- package/bridge/native/rea_lldb_tracer.py +303 -0
- package/bridge/process/ProcessRunTokenReader.swift +263 -0
- package/bridge/process/ProcessRunTokenReaderMain.swift +35 -0
- package/bridge/pwndbg/core_context.py +101 -0
- package/bridge/pwndbg/launch.py +39 -0
- package/bridge/pwndbg/launch_impl.py +34 -0
- package/bridge/pwntools/decoder_runtime.py +59 -0
- package/bridge/pwntools/layout.py +39 -0
- package/bridge/pwntools/layout_impl.py +309 -0
- package/bridge/pwntools/recorded_crash.py +39 -0
- package/bridge/pwntools/recorded_crash_impl.py +143 -0
- package/dist/android/JadxProvider.js +1 -0
- package/dist/application/CapabilityInventory.js +21 -0
- package/dist/application/DirectAnalysis.js +97 -23
- package/dist/application/EvidenceBundleFiles.js +1 -1
- package/dist/application/ReconstructionObligationCandidates.js +5 -1
- package/dist/application/WebNetworkCapturePort.js +1 -0
- package/dist/application/WebNetworkCaptureService.js +132 -0
- package/dist/application/WindowsCapabilities.js +1 -1
- package/dist/application/binary/AnalysisSnapshotCache.js +49 -6
- package/dist/application/binary/BinarySession.js +38 -10
- package/dist/application/binary/BinarySessionOpen.js +16 -3
- package/dist/application/binary/BinarySessionRecords.js +20 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutPort.js +1 -0
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +57 -0
- package/dist/application/binaryDiagnostics/RecordedCrashPort.js +1 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +60 -0
- package/dist/application/evm/EvmInterfacePort.js +1 -0
- package/dist/application/evm/EvmInterfaceService.js +62 -0
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -2
- package/dist/application/javascript/JavaScriptApplicationService.js +15 -2
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +42 -23
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +26 -2
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +74 -24
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +23 -10
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +145 -70
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +14 -15
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +41 -1
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +7 -7
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -9
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +118 -12
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +5 -5
- package/dist/application/{ProcessCli.js → process/ProcessCli.js} +10 -10
- package/dist/application/{ProcessEvidence.js → process/ProcessEvidence.js} +4 -4
- package/dist/artifacts/ArtifactProvider.js +30 -3
- package/dist/artifacts/ArtifactProviderMetadata.js +2 -1
- package/dist/artifacts/ZipArtifactReader.js +3 -0
- package/dist/artifacts/apple/DylibResolutionReader.js +259 -0
- package/dist/artifacts/apple/MachoLoadCommandReader.js +294 -0
- package/dist/{application → artifacts/extraction}/ArtifactExtraction.js +10 -10
- package/dist/{application → artifacts/inventory}/ArtifactGraphConstruction.js +3 -3
- package/dist/{application → artifacts/inventory}/ArtifactInventory.js +4 -4
- package/dist/{application/ArtifactInventory → artifacts/inventory}/classify.js +2 -2
- package/dist/{application/ArtifactInventory → artifacts/inventory}/reader.js +5 -5
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanCanonical.js +3 -3
- package/dist/{application/ArtifactInventory → artifacts/inventory}/scanReader.js +5 -5
- package/dist/artifacts/readStableArtifact.js +20 -4
- package/dist/browser/CdpCaptureEventHandlers.js +90 -2
- package/dist/browser/CdpCaptureEvents.js +9 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +12 -3
- package/dist/browser/history/CaptureFailures.js +101 -0
- package/dist/browser/history/CaptureFormatError.js +10 -0
- package/dist/browser/history/CaptureRedaction.js +65 -0
- package/dist/browser/history/CaptureRelease.js +12 -0
- package/dist/browser/history/HarCapture.js +165 -0
- package/dist/browser/history/HarCaptureAdapter.js +20 -0
- package/dist/browser/history/HarCaptureProcess.js +57 -0
- package/dist/browser/history/HarJson.js +91 -0
- package/dist/browser/history/HarSchema.js +72 -0
- package/dist/browser/history/HistoricalCaptureDecoder.js +186 -0
- package/dist/browser/history/HistoricalCaptureFormatAdapter.js +1 -0
- package/dist/browser/history/MitmproxyCaptureAdapter.js +42 -0
- package/dist/cli/artifactCommands.js +26 -1
- package/dist/cli/binaryDiagnosticsCommands.js +39 -0
- package/dist/cli/coreAnalysisCommands.js +2 -2
- package/dist/cli/coreBinaryCommands.js +8 -8
- package/dist/cli/electronCommands.js +16 -9
- package/dist/cli/evmCommands.js +24 -0
- package/dist/cli/firmwareCommands.js +6 -3
- package/dist/cli/javascriptApplicationAnalysis.js +16 -3
- package/dist/cli/jsonOutput.js +133 -0
- package/dist/cli/nativeCallCommands.js +35 -0
- package/dist/cli/processCommands.js +1 -1
- package/dist/cli/streamedJsonOutput.js +56 -0
- package/dist/cli/utilityCommands.js +2 -0
- package/dist/cli/webNetworkCaptureCommands.js +40 -0
- package/dist/cli.js +9 -3
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +6 -0
- package/dist/cliJsonInput.js +30 -1
- package/dist/cliOutput.js +21 -6
- package/dist/composition/binaryDiagnostics.js +8 -0
- package/dist/composition/evm.js +4 -0
- package/dist/composition/webNetworkCaptures.js +6 -0
- package/dist/contracts/artifactToolContracts.js +6 -0
- package/dist/contracts/browserCaptureToolInputSchema.js +43 -0
- package/dist/contracts/browserToolContracts.js +4 -3
- package/dist/contracts/errorSchemas.js +8 -1
- package/dist/contracts/evm/evmToolContracts.js +20 -0
- package/dist/contracts/investigationExamples.js +2 -2
- package/dist/contracts/managed/managedToolContracts.js +7 -3
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +42 -0
- package/dist/contracts/native/nativeToolContracts.js +17 -1
- package/dist/contracts/officialToolContracts.js +12 -9
- package/dist/contracts/process/processCaptureExample.js +2 -0
- package/dist/contracts/sessionLifecycleInputs.js +22 -5
- package/dist/contracts/sessionStatusContract.js +10 -2
- package/dist/contracts/sessionToolContracts.js +8 -1
- package/dist/contracts/sessionToolSchemas.js +10 -3
- package/dist/contracts/toolContractExamples.js +1 -1
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +30 -0
- package/dist/contracts/toolOutputSchemaGroups.js +5 -1
- package/dist/contracts/toolOutputSchemaPrimitives.js +1 -1
- package/dist/contracts/webNetworkCaptureToolContracts.js +24 -0
- package/dist/domain/analysisErrorBase.js +15 -0
- package/dist/domain/analysisErrorCore.js +59 -5
- package/dist/domain/analysisErrorPresentation.js +29 -1
- package/dist/domain/analysisErrorProjection.js +52 -2
- package/dist/domain/analysisSnapshot.js +166 -2
- package/dist/domain/apple/dyldPaths.js +81 -0
- package/dist/domain/apple/dylibResolution.js +367 -0
- package/dist/domain/apple/dylibResolutionFindings.js +75 -0
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/browserObservation.js +1 -1
- package/dist/domain/browserObservationSchemas.js +13 -0
- package/dist/domain/browserScenarioValues.js +9 -2
- package/dist/domain/callPathSchemas.js +1 -1
- package/dist/domain/canonicalDigest.js +13 -1
- package/dist/domain/changedBehavior.js +3 -3
- package/dist/domain/comparisonStatus.js +2 -30
- package/dist/domain/conformanceTrustGate.js +0 -16
- package/dist/domain/evidence.js +17 -5
- package/dist/domain/evm/evmInterface.js +63 -0
- package/dist/domain/explicitSensitiveFailure.js +92 -0
- package/dist/domain/explicitSensitiveValues.js +10 -0
- package/dist/domain/firmware/firmwareAnalysis.js +8 -1
- package/dist/domain/javascript/electronActiveObservation.js +9 -4
- package/dist/domain/javascript/htmlArtifactReferences.js +40 -0
- package/dist/domain/javascript/javascriptExportShapeComparison.js +21 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +0 -10
- package/dist/domain/javascript/javascriptSemanticGraph.js +21 -5
- package/dist/domain/jsonValue.js +4 -0
- package/dist/domain/localPath.js +2 -0
- package/dist/domain/native/binaryLayout.js +357 -0
- package/dist/domain/native/nativeCallObservation.js +164 -0
- package/dist/domain/native/objcSwiftMetadata.js +0 -39
- package/dist/domain/native/recordedCrash.js +266 -0
- package/dist/domain/native/recordedCrashNoteCoverage.js +73 -0
- package/dist/domain/{processCapture.js → process/processCapture.js} +139 -2
- package/dist/domain/{processCaptureExample.js → process/processCaptureExample.js} +5 -0
- package/dist/domain/process/processCaptureParsing.js +54 -0
- package/dist/domain/{processCaptureValidation.js → process/processCaptureValidation.js} +18 -2
- package/dist/domain/{processComparison.js → process/processComparison.js} +1 -1
- package/dist/domain/{processObservation.js → process/processObservation.js} +1 -1
- package/dist/domain/{processTraceSpecification.js → process/processTraceSpecification.js} +1 -1
- package/dist/domain/providerSelectionError.js +4 -2
- package/dist/domain/reconstructionVerification.js +3 -3
- package/dist/domain/reconstructionVerificationSchemas.js +1 -1
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/staticRuntimeCorrelation.js +3 -3
- package/dist/domain/webCaptureDiff.js +1 -0
- package/dist/domain/webNetworkCapture.js +118 -0
- package/dist/domain/webNetworkCaptureCoordinates.js +58 -0
- package/dist/dotnet/ManagedExceptionRegionValidation.js +41 -0
- package/dist/dotnet/ManagedMemberInspector.js +4 -2
- package/dist/dotnet/ManagedMemberInspectorCore.js +38 -32
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +23 -7
- package/dist/dotnet/ManagedMemberRows.js +14 -3
- package/dist/dotnet/ManagedMetadataHeaps.js +20 -2
- package/dist/dotnet/ManagedMetadataInventory.js +38 -28
- package/dist/dotnet/ManagedMetadataInventoryRows.js +24 -10
- package/dist/dotnet/ManagedMethodBodyReader.js +7 -1
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +15 -3
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +3 -1
- package/dist/dotnet/ManagedPeReader.js +11 -0
- package/dist/evm/EvmBytecodeCarrier.js +21 -0
- package/dist/evm/EvmWorkerLimits.js +40 -0
- package/dist/evm/EvmoleFailures.js +126 -0
- package/dist/evm/EvmoleInterfaceAdapter.js +53 -0
- package/dist/evm/EvmoleInterfaceProvider.js +273 -0
- package/dist/evm/EvmoleInterfaceWorker.js +87 -0
- package/dist/evm/EvmoleRelease.js +16 -0
- package/dist/firmware/FirmwareCommand.js +1 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraLauncher.js +1 -0
- package/dist/ghidra/GhidraProvider.js +2 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +1 -1
- package/dist/hopper/BridgeLauncher.js +2 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +4 -2
- package/dist/javascript/recovery/WakaruCommand.js +3 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +1 -0
- package/dist/native/CommandRunner.js +2 -1
- package/dist/native/LldbCallTracer.js +278 -0
- package/dist/native/NativeCallObservation.js +135 -0
- package/dist/native/NativeMacOSProvider.js +19 -3
- package/dist/native/NativeMacOSProviderMetadata.js +8 -3
- package/dist/native/pwndbg/PwndbgCoreContext.js +160 -0
- package/dist/native/pwntools/PwntoolsDecoder.js +203 -0
- package/dist/native/pwntools/PwntoolsFailures.js +180 -0
- package/dist/native/pwntools/PwntoolsLayoutProvider.js +36 -0
- package/dist/native/pwntools/PwntoolsRecordedCrashProvider.js +75 -0
- package/dist/native/pwntools/PwntoolsRelease.js +19 -0
- package/dist/native/pwntools/PwntoolsResourceLimits.js +76 -0
- package/dist/native/pwntools/RecordedCrashSourceBindings.js +46 -0
- package/dist/native/pwntools/RecordedCrashStructureBindings.js +101 -0
- package/dist/process/DarwinProcessRunTokenReader.js +294 -0
- package/dist/process/OwnedCommand.js +113 -0
- package/dist/process/ProcessOwnership.js +263 -33
- package/dist/process/ProcessOwnershipObservation.js +161 -24
- package/dist/process/ProviderProcess.js +30 -3
- package/dist/{application → process/capture}/ProcessCaptureCapability.js +15 -0
- package/dist/{application → process/capture}/ProcessCaptureError.js +17 -1
- package/dist/process/capture/ProcessCaptureLifecycle.js +615 -0
- package/dist/{application → process/capture}/ProcessHarness.js +195 -29
- package/dist/{application → process/capture}/ProcessSampling.js +2 -2
- package/dist/server/createServer.js +22 -0
- package/dist/server/promptCompletion.js +10 -3
- package/dist/server/registerBinaryDiagnosticsTools.js +17 -0
- package/dist/server/registerEvidenceTools.js +1 -1
- package/dist/server/registerEvmTools.js +17 -0
- package/dist/server/registerProcessComparisonTool.js +1 -1
- package/dist/server/registerRecordedCrashTools.js +17 -0
- package/dist/server/registerSessionTools.js +2 -2
- package/dist/server/registerWebNetworkCaptureTool.js +28 -0
- package/dist/server/sessionAvailabilityPolicy.js +3 -0
- package/dist/server/sessionToolPolicies.js +1 -1
- package/dist/server/toolResult.js +1 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +37 -9
- package/scripts/rea.mjs +11 -3
- package/skills/reverse-engineer-anything/SKILL.md +23 -3
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +29 -0
- package/third_party/README.md +60 -0
- package/third_party/evmole/LICENSE +21 -0
- package/third_party/evmole/README.md +22 -0
- package/third_party/pwndbg/LICENSE.md +21 -0
- package/third_party/pwndbg/README.md +23 -0
- package/third_party/pwntools/README.md +40 -0
- package/dist/application/AuthorizedArtifactInventory.js +0 -7
- package/dist/application/ProcessCaptureLifecycle.js +0 -299
- package/dist/application/StoreFileLock.js +0 -124
- package/dist/contracts/processCaptureExample.js +0 -2
- package/dist/domain/bytecodeProvider.js +0 -178
- package/dist/domain/customProtocolCapture.js +0 -137
- package/dist/domain/eventProcessTree.js +0 -225
- package/dist/domain/mobileApplicationInvestigation.js +0 -159
- package/dist/domain/packageAnalysis.js +0 -123
- package/dist/domain/peInspection.js +0 -197
- package/dist/domain/processCaptureParsing.js +0 -21
- package/dist/domain/protocolCapture.js +0 -217
- package/dist/domain/runtimeIdentification.js +0 -212
- package/dist/generatedMcpToolCatalog.js +0 -37
- /package/dist/application/{ArtifactExtractionDestination.js → artifacts/ArtifactExtractionDestination.js} +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/policy.js +0 -0
- /package/dist/{application/ArtifactInventory → artifacts/inventory}/types.js +0 -0
- /package/dist/domain/{processEvidenceProvider.js → process/processEvidenceProvider.js} +0 -0
- /package/dist/domain/{processScenario.js → process/processScenario.js} +0 -0
- /package/dist/domain/{processTraceComparison.js → process/processTraceComparison.js} +0 -0
- /package/dist/domain/{processTraceDimensionProjection.js → process/processTraceDimensionProjection.js} +0 -0
- /package/dist/domain/{processTraceEvaluation.js → process/processTraceEvaluation.js} +0 -0
- /package/dist/{application → process/capture}/FilesystemSnapshot.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureEnvironment.js +0 -0
- /package/dist/{application → process/capture}/ProcessCaptureJournal.js +0 -0
- /package/dist/{application → process/capture}/ProcessFilesystemEffects.js +0 -0
- /package/dist/{application → process/capture}/ProcessNormalization.js +0 -0
- /package/dist/{application → process/capture}/ProcessScenarioRuntimeValidation.js +0 -0
- /package/dist/{application → process/capture}/ProcessTimer.js +0 -0
- /package/dist/{application → process/capture}/TerminalRenderer.js +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js";
|
|
3
|
+
import { createEvidence } from "../../domain/evidence.js";
|
|
4
|
+
import { inspectBinaryLayoutInputSchema, binaryLayoutSchema, } from "../../domain/native/binaryLayout.js";
|
|
5
|
+
import { projectInputIssues } from "../../domain/inputIssueProjection.js";
|
|
6
|
+
import { err, ok } from "../../domain/result.js";
|
|
7
|
+
const OPERATION = "inspect_binary_layout";
|
|
8
|
+
/** Shared CLI/MCP validation and Evidence composition for offline layout inspection. */
|
|
9
|
+
export class BinaryLayoutService {
|
|
10
|
+
provider;
|
|
11
|
+
constructor(provider) {
|
|
12
|
+
this.provider = provider;
|
|
13
|
+
}
|
|
14
|
+
/** Bind complete observations to the caller-selected artifact before creating Evidence. */
|
|
15
|
+
async inspect(rawInput, options) {
|
|
16
|
+
if (options?.signal?.aborted)
|
|
17
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
18
|
+
const input = inspectBinaryLayoutInputSchema.safeParse(rawInput);
|
|
19
|
+
if (!input.success)
|
|
20
|
+
return err(new AnalysisInputError(OPERATION, { cause: input.error }, projectInputIssues(input.error.issues, rawInput)));
|
|
21
|
+
if (!isAbsolute(input.data.path))
|
|
22
|
+
return err(new AnalysisInputError(OPERATION, undefined, [
|
|
23
|
+
{
|
|
24
|
+
path: ["path"],
|
|
25
|
+
reason: "invalid_format",
|
|
26
|
+
message: "Expected an absolute filesystem path on this host.",
|
|
27
|
+
},
|
|
28
|
+
]));
|
|
29
|
+
const inspected = await this.provider.inspect(input.data, options);
|
|
30
|
+
if (!inspected.ok)
|
|
31
|
+
return inspected;
|
|
32
|
+
const diagnostics = binaryLayoutSchema.shape.diagnostics.safeParse(inspected.value.diagnostics);
|
|
33
|
+
const outputOptions = diagnostics.success
|
|
34
|
+
? { capturedOutput: diagnostics.data }
|
|
35
|
+
: undefined;
|
|
36
|
+
if (options?.signal?.aborted)
|
|
37
|
+
return err(new AnalysisCancelledError(OPERATION, outputOptions));
|
|
38
|
+
const report = binaryLayoutSchema.safeParse(inspected.value);
|
|
39
|
+
if (!report.success || report.data.artifact.path !== input.data.path)
|
|
40
|
+
return err(new AnalysisOutputError(OPERATION, "Binary layout provider returned malformed evidence or changed the selected artifact identity.", outputOptions));
|
|
41
|
+
const value = report.data;
|
|
42
|
+
return ok(createEvidence({
|
|
43
|
+
path: value.artifact.path,
|
|
44
|
+
format: "elf",
|
|
45
|
+
architecture: "x86_64",
|
|
46
|
+
sha256: value.artifact.sha256,
|
|
47
|
+
}, this.provider.identity, {
|
|
48
|
+
operation: OPERATION,
|
|
49
|
+
parameters: input.data,
|
|
50
|
+
result: value,
|
|
51
|
+
rawResult: value,
|
|
52
|
+
confidence: "observed",
|
|
53
|
+
limitations: value.limitations,
|
|
54
|
+
locations: [{ kind: "artifact-path", path: value.artifact.path }],
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js";
|
|
3
|
+
import { createEvidence } from "../../domain/evidence.js";
|
|
4
|
+
import { inspectRecordedCrashInputSchema, recordedCrashSchema, } from "../../domain/native/recordedCrash.js";
|
|
5
|
+
import { projectInputIssues } from "../../domain/inputIssueProjection.js";
|
|
6
|
+
import { err, ok } from "../../domain/result.js";
|
|
7
|
+
const OPERATION = "inspect_recorded_crash";
|
|
8
|
+
/** Shared CLI/MCP validation and Evidence composition for recorded crash inspection. */
|
|
9
|
+
export class RecordedCrashService {
|
|
10
|
+
provider;
|
|
11
|
+
constructor(provider) {
|
|
12
|
+
this.provider = provider;
|
|
13
|
+
}
|
|
14
|
+
/** Bind complete observations to the caller-selected artifact before creating Evidence. */
|
|
15
|
+
async inspect(rawInput, options) {
|
|
16
|
+
if (options?.signal?.aborted)
|
|
17
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
18
|
+
const input = inspectRecordedCrashInputSchema.safeParse(rawInput);
|
|
19
|
+
if (!input.success)
|
|
20
|
+
return err(new AnalysisInputError(OPERATION, { cause: input.error }, projectInputIssues(input.error.issues, rawInput)));
|
|
21
|
+
if (!isAbsolute(input.data.path))
|
|
22
|
+
return err(new AnalysisInputError(OPERATION, undefined, [
|
|
23
|
+
{
|
|
24
|
+
path: ["path"],
|
|
25
|
+
reason: "invalid_format",
|
|
26
|
+
message: "Expected an absolute filesystem path on this host.",
|
|
27
|
+
},
|
|
28
|
+
]));
|
|
29
|
+
const inspected = await this.provider.inspect(input.data, options);
|
|
30
|
+
if (!inspected.ok)
|
|
31
|
+
return inspected;
|
|
32
|
+
const diagnostics = recordedCrashSchema.shape.diagnostics.safeParse(inspected.value.diagnostics);
|
|
33
|
+
const outputOptions = diagnostics.success
|
|
34
|
+
? { capturedOutput: diagnostics.data }
|
|
35
|
+
: undefined;
|
|
36
|
+
if (options?.signal?.aborted)
|
|
37
|
+
return err(new AnalysisCancelledError(OPERATION, outputOptions));
|
|
38
|
+
const report = recordedCrashSchema.safeParse(inspected.value);
|
|
39
|
+
if (!report.success ||
|
|
40
|
+
report.data.artifact.path !== input.data.path ||
|
|
41
|
+
(report.data.debugger.status === "available") !==
|
|
42
|
+
input.data.include_debugger_context)
|
|
43
|
+
return err(new AnalysisOutputError(OPERATION, "Recorded crash provider returned malformed evidence or changed the selected artifact identity.", outputOptions));
|
|
44
|
+
const value = report.data;
|
|
45
|
+
return ok(createEvidence({
|
|
46
|
+
path: value.artifact.path,
|
|
47
|
+
format: "elf",
|
|
48
|
+
architecture: "x86_64",
|
|
49
|
+
sha256: value.artifact.sha256,
|
|
50
|
+
}, this.provider.identity, {
|
|
51
|
+
operation: OPERATION,
|
|
52
|
+
parameters: input.data,
|
|
53
|
+
result: value,
|
|
54
|
+
rawResult: value,
|
|
55
|
+
confidence: value.debugger.status === "available" ? "derived" : "observed",
|
|
56
|
+
limitations: value.limitations,
|
|
57
|
+
locations: [{ kind: "artifact-path", path: value.artifact.path }],
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { AnalysisCancelledError, AnalysisInputError, AnalysisOutputError, } from "../../domain/analysisErrorCore.js";
|
|
4
|
+
import { createEvidence } from "../../domain/evidence.js";
|
|
5
|
+
import { inspectEvmInterfaceInputSchema, evmInterfaceSchema, } from "../../domain/evm/evmInterface.js";
|
|
6
|
+
import { projectInputIssues } from "../../domain/inputIssueProjection.js";
|
|
7
|
+
import { err, ok } from "../../domain/result.js";
|
|
8
|
+
const OPERATION = "inspect_evm_interface";
|
|
9
|
+
const diagnosticsSchema = z.object({
|
|
10
|
+
diagnostics: evmInterfaceSchema.shape.diagnostics,
|
|
11
|
+
});
|
|
12
|
+
/** Shared carrier validation and typed inline Evidence for CLI/MCP. */
|
|
13
|
+
export class EvmInterfaceService {
|
|
14
|
+
provider;
|
|
15
|
+
constructor(provider) {
|
|
16
|
+
this.provider = provider;
|
|
17
|
+
}
|
|
18
|
+
/** Preserve selected byte identity while clearly labeling recovered ABI candidates as inferences. */
|
|
19
|
+
async inspect(rawInput, options) {
|
|
20
|
+
if (options?.signal?.aborted)
|
|
21
|
+
return err(new AnalysisCancelledError(OPERATION));
|
|
22
|
+
const input = inspectEvmInterfaceInputSchema.safeParse(rawInput);
|
|
23
|
+
if (!input.success)
|
|
24
|
+
return err(new AnalysisInputError(OPERATION, { cause: input.error }, projectInputIssues(input.error.issues, rawInput)));
|
|
25
|
+
if (!isAbsolute(input.data.path))
|
|
26
|
+
return err(new AnalysisInputError(OPERATION, undefined, [
|
|
27
|
+
{
|
|
28
|
+
path: ["path"],
|
|
29
|
+
reason: "invalid_format",
|
|
30
|
+
message: "Expected an absolute filesystem path on this host.",
|
|
31
|
+
},
|
|
32
|
+
]));
|
|
33
|
+
const inspected = await this.provider.inspect(input.data, options);
|
|
34
|
+
if (!inspected.ok)
|
|
35
|
+
return inspected;
|
|
36
|
+
const diagnostics = diagnosticsSchema.safeParse(inspected.value.result);
|
|
37
|
+
const outputOptions = diagnostics.success
|
|
38
|
+
? { capturedOutput: diagnostics.data.diagnostics }
|
|
39
|
+
: undefined;
|
|
40
|
+
if (options?.signal?.aborted)
|
|
41
|
+
return err(new AnalysisCancelledError(OPERATION, outputOptions));
|
|
42
|
+
const execution = inspected.value;
|
|
43
|
+
const report = evmInterfaceSchema.safeParse(execution.result);
|
|
44
|
+
if (!report.success ||
|
|
45
|
+
report.data.artifact.path !== input.data.path ||
|
|
46
|
+
report.data.artifact.encoding !== input.data.encoding ||
|
|
47
|
+
execution.subject?.path !== input.data.path ||
|
|
48
|
+
execution.subject.sha256 !== report.data.artifact.sha256)
|
|
49
|
+
return err(new AnalysisOutputError(OPERATION, "Interface adapter returned malformed data or changed the selected carrier identity/encoding.", outputOptions));
|
|
50
|
+
return ok(createEvidence(execution.subject, execution.provider, {
|
|
51
|
+
operation: OPERATION,
|
|
52
|
+
parameters: input.data,
|
|
53
|
+
result: report.data,
|
|
54
|
+
...(execution.rawResult === null
|
|
55
|
+
? {}
|
|
56
|
+
: { rawResult: execution.rawResult }),
|
|
57
|
+
confidence: "inferred",
|
|
58
|
+
locations: execution.locations,
|
|
59
|
+
limitations: execution.limitations,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createEvidence, } from "../../domain/evidence.js";
|
|
2
|
-
import { jsonValueSchema } from "../../domain/jsonValue.js";
|
|
3
2
|
import { JAVASCRIPT_APPLICATION_PROVIDER } from "../InvestigationProviders.js";
|
|
4
3
|
/** Create Evidence for one deterministic local JavaScript application graph. */
|
|
5
4
|
export const createJavaScriptApplicationEvidence = (input, result) => createEvidence({
|
|
@@ -10,7 +9,7 @@ export const createJavaScriptApplicationEvidence = (input, result) => createEvid
|
|
|
10
9
|
predicateType: "rea.javascript-application-analysis",
|
|
11
10
|
operation: "analyze_javascript_application",
|
|
12
11
|
parameters: parameters(input),
|
|
13
|
-
result
|
|
12
|
+
result,
|
|
14
13
|
rawResult: null,
|
|
15
14
|
confidence: "derived",
|
|
16
15
|
authority: "shipped-artifact",
|
|
@@ -30,13 +30,26 @@ export const analyzeJavaScriptApplicationValidated = async (input, options = {})
|
|
|
30
30
|
const reconstructed = await reconstructJavaScriptArtifact({
|
|
31
31
|
input_path: input.input_path,
|
|
32
32
|
format: input.format,
|
|
33
|
-
}, options.signal);
|
|
33
|
+
}, options.signal, options.progress);
|
|
34
34
|
const { electron_summary: summary, ...application } = reconstructed;
|
|
35
|
+
await options.progress?.report({
|
|
36
|
+
phase: "validate_javascript_application_result",
|
|
37
|
+
completed: 0,
|
|
38
|
+
total: 1,
|
|
39
|
+
message: "Validating the application analysis result",
|
|
40
|
+
});
|
|
35
41
|
const result = javascriptApplicationAnalysisResultSchema.parse({
|
|
36
42
|
...application,
|
|
37
43
|
summary,
|
|
38
44
|
limitations: reconstructed.graph.limitations,
|
|
39
45
|
});
|
|
46
|
+
await options.progress?.report({
|
|
47
|
+
phase: "create_javascript_application_evidence",
|
|
48
|
+
completed: 0,
|
|
49
|
+
total: 1,
|
|
50
|
+
message: "Creating and hashing application analysis Evidence",
|
|
51
|
+
});
|
|
52
|
+
const evidence = createJavaScriptApplicationEvidence(input, result);
|
|
40
53
|
await options.progress?.report({
|
|
41
54
|
phase: "analyze_javascript_application",
|
|
42
55
|
completed: 1,
|
|
@@ -44,7 +57,7 @@ export const analyzeJavaScriptApplicationValidated = async (input, options = {})
|
|
|
44
57
|
message: "Application graph and Electron boundaries reconstructed",
|
|
45
58
|
terminal: true,
|
|
46
59
|
});
|
|
47
|
-
return ok(
|
|
60
|
+
return ok(evidence);
|
|
48
61
|
}
|
|
49
62
|
catch (cause) {
|
|
50
63
|
if (cause instanceof ArtifactReaderFailure)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { setImmediate } from "node:timers/promises";
|
|
2
3
|
import { analyzeParsedJavaScriptStaticSource } from "../../domain/javascript/javascriptStaticAnalysis.js";
|
|
3
4
|
import { analyzeParsedJavaScriptSemantics } from "../../domain/javascript/javascriptSemanticAnalysis.js";
|
|
4
5
|
import { parseJavaScriptSource } from "../../domain/javascript/javascriptSourceParser.js";
|
|
@@ -6,10 +7,39 @@ import { hasValidSourceMapContents } from "../../domain/sourceMapContents.js";
|
|
|
6
7
|
import { flattenSourceMapLeaves } from "../../domain/sourceMapEnvelope.js";
|
|
7
8
|
import { failedJavaScriptStaticAnalysis } from "../../domain/javascript/javascriptStaticAnalysisHelpers.js";
|
|
8
9
|
import { analyzeJavaScriptJsonModule } from "./JavaScriptJsonModules.js";
|
|
10
|
+
import { htmlArtifactReferences } from "../../domain/javascript/htmlArtifactReferences.js";
|
|
9
11
|
/** Analyze every text source from the artifact without a result quota. */
|
|
10
|
-
export const analyzeJavaScriptArtifactFiles = (fileSet) =>
|
|
12
|
+
export const analyzeJavaScriptArtifactFiles = (fileSet) => analyzeArtifactFiles(fileSet, (_file, ir) => ir);
|
|
13
|
+
/** Project each file's full IR immediately, retaining only later module facts. */
|
|
14
|
+
export const analyzeAndProjectJavaScriptArtifactFiles = async (fileSet, projectSemantics, beforeFile) => {
|
|
11
15
|
const state = emptyArtifactAnalysis();
|
|
12
|
-
const
|
|
16
|
+
const projectFileSemantics = (file, ir) => {
|
|
17
|
+
projectSemantics(file, ir);
|
|
18
|
+
const programScopes = ir.scopes.filter(({ kind }) => kind === "program");
|
|
19
|
+
const programScopeId = programScopes[0]?.scopeId;
|
|
20
|
+
const localNames = new Set(ir.moduleLinks.map(({ localName }) => localName));
|
|
21
|
+
const callableIds = new Set(ir.moduleLinks.map(({ callableId }) => callableId));
|
|
22
|
+
return {
|
|
23
|
+
scopes: programScopes,
|
|
24
|
+
bindings: ir.bindings.filter(({ name, scopeId }) => scopeId === programScopeId && localNames.has(name)),
|
|
25
|
+
callables: ir.callables.filter(({ callableId }) => callableIds.has(callableId)),
|
|
26
|
+
moduleLinks: ir.moduleLinks,
|
|
27
|
+
coverage: ir.coverage,
|
|
28
|
+
limitations: ir.limitations,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
const context = { state, projectSemantics: projectFileSemantics };
|
|
32
|
+
for (const [index, file] of fileSet.files.entries()) {
|
|
33
|
+
// Let progress, cancellation and garbage collection run between files.
|
|
34
|
+
await setImmediate();
|
|
35
|
+
await beforeFile?.(file, index, fileSet.files.length);
|
|
36
|
+
analyzeArtifactFile(file, context);
|
|
37
|
+
}
|
|
38
|
+
return finalizeArtifactAnalysis(state);
|
|
39
|
+
};
|
|
40
|
+
const analyzeArtifactFiles = (fileSet, projectSemantics) => {
|
|
41
|
+
const state = emptyArtifactAnalysis();
|
|
42
|
+
const context = { state, projectSemantics };
|
|
13
43
|
for (const file of fileSet.files)
|
|
14
44
|
analyzeArtifactFile(file, context);
|
|
15
45
|
return finalizeArtifactAnalysis(state);
|
|
@@ -62,7 +92,9 @@ const analyzeArtifactFile = (file, context) => {
|
|
|
62
92
|
state.files.push({
|
|
63
93
|
file,
|
|
64
94
|
javascript: analysis,
|
|
65
|
-
semantic: semantics === null
|
|
95
|
+
semantic: semantics === null
|
|
96
|
+
? null
|
|
97
|
+
: { ir: context.projectSemantics(file, semantics) },
|
|
66
98
|
});
|
|
67
99
|
state.visitedNodes += analysis.visited_ast_nodes;
|
|
68
100
|
state.findings += staticFindings + (semantics?.moduleLinks.length ?? 0);
|
|
@@ -137,26 +169,13 @@ const unavailablePackage = (file, limitation) => ({
|
|
|
137
169
|
limitation,
|
|
138
170
|
});
|
|
139
171
|
const parseHtmlScripts = (path, text) => {
|
|
140
|
-
const scripts =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const start = match.index;
|
|
148
|
-
scripts.push({
|
|
149
|
-
html_path: path,
|
|
150
|
-
script_path: script,
|
|
151
|
-
base_href: baseHref,
|
|
152
|
-
location: rangeForOffsets(text, start, start + match[0].length),
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
return scripts;
|
|
156
|
-
};
|
|
157
|
-
const htmlBaseHref = (text) => {
|
|
158
|
-
const match = /<base\b[^>]*\bhref\s*=\s*(["'])([^"']+)\1[^>]*>/iu.exec(text);
|
|
159
|
-
return match?.[2] ?? null;
|
|
172
|
+
const { scripts, baseHref } = htmlArtifactReferences(text);
|
|
173
|
+
return scripts.map(({ scriptPath, startOffset, endOffset }) => ({
|
|
174
|
+
html_path: path,
|
|
175
|
+
script_path: scriptPath,
|
|
176
|
+
base_href: baseHref,
|
|
177
|
+
location: rangeForOffsets(text, startOffset, endOffset),
|
|
178
|
+
}));
|
|
160
179
|
};
|
|
161
180
|
const parseSourceMap = (file) => {
|
|
162
181
|
if (!file.text.included)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { addArtifactContainsEdge, addStaticInferenceEdge, createElectronRoleNode, linkElectronRoleToAsset, } from "./JavaScriptArtifactGraphContext.js";
|
|
2
|
-
import { artifactObservationEvidence } from "./JavaScriptArtifactGraphEvidence.js";
|
|
2
|
+
import { artifactObservationEvidence, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
|
|
3
3
|
import { completeApplicationCoverage } from "../../domain/javascript/javascriptApplicationEvidenceSchemas.js";
|
|
4
4
|
import { resolveArtifactPathByContext } from "./JavaScriptArtifactPathResolution.js";
|
|
5
5
|
/** Project HTML renderer entrypoints and their local script assets. */
|
|
@@ -46,8 +46,32 @@ export const addJavaScriptHtmlRoles = (context) => {
|
|
|
46
46
|
htmlBaseHref: script.base_href,
|
|
47
47
|
});
|
|
48
48
|
const resolvedPath = resolution.resolved_path;
|
|
49
|
-
if (resolvedPath === null)
|
|
49
|
+
if (resolvedPath === null) {
|
|
50
|
+
context.accumulator.addNode({
|
|
51
|
+
kind: role.kind,
|
|
52
|
+
identity: role.identity,
|
|
53
|
+
observations: [
|
|
54
|
+
{
|
|
55
|
+
label: script.script_path,
|
|
56
|
+
properties: {
|
|
57
|
+
mechanism: "html-script-reference",
|
|
58
|
+
script_path: script.script_path,
|
|
59
|
+
base_href: script.base_href,
|
|
60
|
+
...resolution,
|
|
61
|
+
},
|
|
62
|
+
evidence: staticInferenceEvidence({
|
|
63
|
+
sha256: html.sha256,
|
|
64
|
+
path: html.path,
|
|
65
|
+
range: script.location,
|
|
66
|
+
operation: "resolve-html-script-reference",
|
|
67
|
+
coverage: completeApplicationCoverage(),
|
|
68
|
+
limitations: resolution.limitations,
|
|
69
|
+
}),
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
50
73
|
continue;
|
|
74
|
+
}
|
|
51
75
|
const resolved = context.fileNodes.get(resolvedPath);
|
|
52
76
|
if (resolved === undefined)
|
|
53
77
|
continue;
|
|
@@ -14,16 +14,24 @@ const EXTENSIONS = [
|
|
|
14
14
|
const NODE_BUILTINS = new Set(builtinModules.map((name) => name.replace(/^node:/u, "")));
|
|
15
15
|
/** Resolve one declaration under its exact syntax/metadata context. */
|
|
16
16
|
export const resolveArtifactPathByContext = (input) => resolvePackagePath(input, new Set());
|
|
17
|
-
const resolvePackagePath = (input, packageChain, mode = "full") => {
|
|
17
|
+
const resolvePackagePath = (input, packageChain, mode = "full", exportsTargetUrl = false) => {
|
|
18
18
|
const rejected = rejectDeclaration(input);
|
|
19
19
|
if (rejected !== null)
|
|
20
20
|
return rejected;
|
|
21
|
-
const candidate = contextualCandidate(input);
|
|
21
|
+
const candidate = contextualCandidate(input, exportsTargetUrl);
|
|
22
22
|
if (typeof candidate !== "string")
|
|
23
23
|
return candidate;
|
|
24
24
|
const confined = confineCandidate(input, candidate);
|
|
25
25
|
if (typeof confined !== "string")
|
|
26
26
|
return confined;
|
|
27
|
+
if (input.context === "html-reference")
|
|
28
|
+
return outcome(input, resolveFileCandidates(input, [confined]) ?? {
|
|
29
|
+
resolvedPath: null,
|
|
30
|
+
status: "not-found",
|
|
31
|
+
limitations: [
|
|
32
|
+
`The exact HTML resource ${confined} was not found among the selected application files.`,
|
|
33
|
+
],
|
|
34
|
+
});
|
|
27
35
|
const resolved = mode === "files-and-index"
|
|
28
36
|
? (resolveFileCandidates(input, [
|
|
29
37
|
...fileCandidates(confined),
|
|
@@ -48,10 +56,11 @@ const rejectDeclaration = (input) => {
|
|
|
48
56
|
]);
|
|
49
57
|
return null;
|
|
50
58
|
};
|
|
51
|
-
const contextualCandidate = (input) => {
|
|
59
|
+
const contextualCandidate = (input, exportsTargetUrl) => {
|
|
52
60
|
const { context } = input;
|
|
53
|
-
|
|
61
|
+
let declared = context === "html-reference" ||
|
|
54
62
|
context === "url-reference" ||
|
|
63
|
+
exportsTargetUrl ||
|
|
55
64
|
(context === "module-specifier" && input.moduleKind !== "require")
|
|
56
65
|
? stripQueryAndFragment(input.declaredPath)
|
|
57
66
|
: input.declaredPath;
|
|
@@ -72,6 +81,23 @@ const contextualCandidate = (input) => {
|
|
|
72
81
|
return unresolvedOutcome(input, "external", [
|
|
73
82
|
"URL schemes and protocol-relative URLs are outside this local artifact path context.",
|
|
74
83
|
]);
|
|
84
|
+
// Exports targets use URL paths for both loaders; legacy main fields remain literal.
|
|
85
|
+
if (exportsTargetUrl ||
|
|
86
|
+
(context === "module-specifier" && input.moduleKind !== "require")) {
|
|
87
|
+
try {
|
|
88
|
+
declared = decodeURIComponent(declared);
|
|
89
|
+
}
|
|
90
|
+
catch (cause) {
|
|
91
|
+
void cause;
|
|
92
|
+
return unresolvedOutcome(input, "rejected", [
|
|
93
|
+
"The module URL path contains malformed percent encoding.",
|
|
94
|
+
]);
|
|
95
|
+
}
|
|
96
|
+
if (declared.includes("\0"))
|
|
97
|
+
return unresolvedOutcome(input, "rejected", [
|
|
98
|
+
"The decoded module URL path contains NUL.",
|
|
99
|
+
]);
|
|
100
|
+
}
|
|
75
101
|
const relative = declared.startsWith("/") ? declared.slice(1) : declared;
|
|
76
102
|
return declared.startsWith("/")
|
|
77
103
|
? relative
|
|
@@ -206,6 +232,12 @@ const resolveCandidate = (input, candidate, packageChain) => {
|
|
|
206
232
|
`Directory package metadata ${packagePath} is not valid package JSON.`,
|
|
207
233
|
],
|
|
208
234
|
};
|
|
235
|
+
if (main.status === "rejected")
|
|
236
|
+
return {
|
|
237
|
+
resolvedPath: null,
|
|
238
|
+
status: "rejected",
|
|
239
|
+
limitations: [`Package metadata ${packagePath}: ${main.limitation}`],
|
|
240
|
+
};
|
|
209
241
|
if (main.status === "unmatched")
|
|
210
242
|
return {
|
|
211
243
|
resolvedPath: null,
|
|
@@ -242,7 +274,7 @@ const resolveCandidate = (input, candidate, packageChain) => {
|
|
|
242
274
|
return index;
|
|
243
275
|
}
|
|
244
276
|
// Preserve recursive artifact package lookup only after legacy file/index fallbacks.
|
|
245
|
-
return candidateOutcome(resolvePackagePath(entryInput, chain));
|
|
277
|
+
return candidateOutcome(resolvePackagePath(entryInput, chain, "full", main.source === "exports"));
|
|
246
278
|
};
|
|
247
279
|
const candidateOutcome = (nested) => nested.resolution_status === "resolved"
|
|
248
280
|
? {
|
|
@@ -299,23 +331,35 @@ const packageEntry = (text, moduleKind, useExports) => {
|
|
|
299
331
|
}
|
|
300
332
|
};
|
|
301
333
|
const packageExport = (value, moduleKind) => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return { status: "invalid" };
|
|
306
|
-
const root = Reflect.get(value, ".") ?? value;
|
|
307
|
-
if (typeof root === "string")
|
|
308
|
-
return packagePathValue(root);
|
|
309
|
-
if (typeof root !== "object" || root === null || Array.isArray(root))
|
|
310
|
-
return { status: "invalid" };
|
|
334
|
+
const root = typeof value === "object" && value !== null && Object.hasOwn(value, ".")
|
|
335
|
+
? Reflect.get(value, ".")
|
|
336
|
+
: value;
|
|
311
337
|
const flattened = exportTargets(root, packageExportConditions(moduleKind));
|
|
312
338
|
if (flattened.kind === "invalid")
|
|
313
|
-
return { status: "
|
|
339
|
+
return { status: "rejected", limitation: flattened.limitation };
|
|
314
340
|
const first = flattened.kind === "unmatched" ? undefined : flattened.values[0];
|
|
315
341
|
return first === undefined
|
|
316
|
-
? {
|
|
342
|
+
? {
|
|
343
|
+
status: "unmatched",
|
|
344
|
+
declared: typeof root === "object" && root !== null ? Object.keys(root) : [],
|
|
345
|
+
}
|
|
317
346
|
: { status: "value", value: first };
|
|
318
347
|
};
|
|
348
|
+
const invalidExportTarget = (value, reason) => ({
|
|
349
|
+
kind: "invalid",
|
|
350
|
+
limitation: `The package exports target ${JSON.stringify(value) ?? String(value)} ${reason}.`,
|
|
351
|
+
});
|
|
352
|
+
// Node checks raw target segments before URL normalization. Compare encoded
|
|
353
|
+
// segment names here; full URL decoding follows array target selection.
|
|
354
|
+
const forbiddenExportSegment = (value) => value
|
|
355
|
+
.slice(2)
|
|
356
|
+
.split(/[\\/]/u)
|
|
357
|
+
.find((raw) => {
|
|
358
|
+
const segment = raw.replace(/%[0-9a-f]{2}/giu, (encoded) => String.fromCharCode(Number.parseInt(encoded.slice(1), 16)));
|
|
359
|
+
return (segment === "." ||
|
|
360
|
+
segment === ".." ||
|
|
361
|
+
segment.toLowerCase() === "node_modules");
|
|
362
|
+
});
|
|
319
363
|
/**
|
|
320
364
|
* Resolve a target in Node's declared order. Explicit null blocks an active
|
|
321
365
|
* condition, whereas an unmatched nested object permits the next condition.
|
|
@@ -323,30 +367,36 @@ const packageExport = (value, moduleKind) => {
|
|
|
323
367
|
* preserves the final invalid-versus-null refusal if no string is selected.
|
|
324
368
|
*/
|
|
325
369
|
const exportTargets = (value, conditions) => {
|
|
326
|
-
if (typeof value === "string")
|
|
327
|
-
|
|
370
|
+
if (typeof value === "string") {
|
|
371
|
+
if (!value.startsWith("./"))
|
|
372
|
+
return invalidExportTarget(value, 'must start with "./"');
|
|
373
|
+
const forbidden = forbiddenExportSegment(value);
|
|
374
|
+
return forbidden === undefined
|
|
328
375
|
? { kind: "targets", values: [value] }
|
|
329
|
-
: {
|
|
376
|
+
: invalidExportTarget(value, `contains forbidden path segment ${JSON.stringify(forbidden)} before URL normalization`);
|
|
377
|
+
}
|
|
330
378
|
if (value === null)
|
|
331
379
|
return { kind: "targets", values: [] };
|
|
332
380
|
if (Array.isArray(value)) {
|
|
333
|
-
let invalid =
|
|
381
|
+
let invalid = null;
|
|
334
382
|
for (const entry of value) {
|
|
335
383
|
const nested = exportTargets(entry, conditions);
|
|
336
384
|
if (nested.kind === "invalid") {
|
|
337
|
-
invalid =
|
|
385
|
+
invalid = nested.limitation;
|
|
338
386
|
continue;
|
|
339
387
|
}
|
|
340
388
|
if (nested.kind === "unmatched")
|
|
341
389
|
continue;
|
|
342
|
-
invalid =
|
|
390
|
+
invalid = null;
|
|
343
391
|
if (nested.values.length > 0)
|
|
344
392
|
return nested;
|
|
345
393
|
}
|
|
346
|
-
return invalid
|
|
394
|
+
return invalid === null
|
|
395
|
+
? { kind: "targets", values: [] }
|
|
396
|
+
: { kind: "invalid", limitation: invalid };
|
|
347
397
|
}
|
|
348
398
|
if (typeof value !== "object")
|
|
349
|
-
return
|
|
399
|
+
return invalidExportTarget(value, "must be a relative string, object, array, or null");
|
|
350
400
|
for (const [condition, target] of Object.entries(value)) {
|
|
351
401
|
if (!conditions.has(condition))
|
|
352
402
|
continue;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { lstat, realpath } from "node:fs/promises";
|
|
2
2
|
import { ArtifactReaderFailure } from "../../artifacts/ArtifactReader.js";
|
|
3
3
|
import { createJavaScriptArtifactReader as createReader } from "../../artifacts/javascript/JavaScriptArtifactReader.js";
|
|
4
|
-
import {
|
|
4
|
+
import { analyzeAndProjectJavaScriptArtifactFiles } from "./JavaScriptArtifactAnalysis.js";
|
|
5
5
|
import { readJavaScriptArtifactFiles } from "../../artifacts/javascript/JavaScriptArtifactFiles.js";
|
|
6
6
|
import { buildJavaScriptArtifactGraph } from "./JavaScriptArtifactGraphBuilder.js";
|
|
7
7
|
import { javascriptArtifactReconstructionInputSchema, } from "./JavaScriptArtifactReconstructionInput.js";
|
|
8
|
-
import { scanCanonicalArtifactInventory } from "
|
|
8
|
+
import { scanCanonicalArtifactInventory } from "../../artifacts/inventory/ArtifactInventory.js";
|
|
9
9
|
import { summarizeElectronBoundaries } from "./ElectronBoundaryAnalysis.js";
|
|
10
|
-
import {
|
|
10
|
+
import { createJavaScriptSemanticGraphProjection } from "./JavaScriptSemanticGraphBuilder.js";
|
|
11
11
|
/** Reconstruct one local ASAR or extracted directory without executing code. */
|
|
12
|
-
export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
12
|
+
export const reconstructJavaScriptArtifact = async (rawInput, signal, progress) => {
|
|
13
|
+
const reportPhase = async (phase, message) => {
|
|
14
|
+
await progress?.report({ phase, completed: 0, total: 1, message });
|
|
15
|
+
};
|
|
13
16
|
const input = javascriptArtifactReconstructionInputSchema.parse(rawInput);
|
|
14
17
|
abortIfNeeded(signal);
|
|
15
18
|
const path = await realpath(input.input_path);
|
|
@@ -19,15 +22,25 @@ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
|
19
22
|
throw new ArtifactReaderFailure("format", `Artifact inventory classified ${path} as ${snapshot.manifest.root_format}, not ${format}`);
|
|
20
23
|
const reader = createReader(path, format);
|
|
21
24
|
try {
|
|
25
|
+
await reportPhase("read_javascript_artifacts", "Reading inventoried JavaScript application sources");
|
|
22
26
|
const files = await readJavaScriptArtifactFiles(reader, snapshot, signal);
|
|
23
|
-
|
|
27
|
+
await reportPhase("parse_javascript_sources", `Parsing and projecting ${String(files.files.length)} application source files`);
|
|
28
|
+
const semanticProjection = createJavaScriptSemanticGraphProjection();
|
|
29
|
+
const analysis = await analyzeAndProjectJavaScriptArtifactFiles(files, semanticProjection.projectFile, async (file, completed, total) => {
|
|
30
|
+
abortIfNeeded(signal);
|
|
31
|
+
await progress?.report({
|
|
32
|
+
phase: "parse_javascript_source",
|
|
33
|
+
completed: 0,
|
|
34
|
+
total: 1,
|
|
35
|
+
message: `Parsing and projecting ${file.path} (${String(completed + 1)}/${String(total)})`,
|
|
36
|
+
});
|
|
37
|
+
abortIfNeeded(signal);
|
|
38
|
+
});
|
|
24
39
|
abortIfNeeded(signal);
|
|
40
|
+
await reportPhase("build_javascript_application_graph", "Constructing application and Electron boundary relationships");
|
|
25
41
|
const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
applicationGraph: graph,
|
|
29
|
-
analysis,
|
|
30
|
-
});
|
|
42
|
+
await reportPhase("build_javascript_semantic_graph", "Binding and validating static semantic relationships");
|
|
43
|
+
const semanticGraph = semanticProjection.finish(snapshot.manifest.root_sha256, graph, analysis);
|
|
31
44
|
return {
|
|
32
45
|
input_path: path,
|
|
33
46
|
format,
|