rea-agents 6.1.0 → 6.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 +7 -5
- package/bridge/ghidra/ReaGhidraBridge.java +32 -4
- package/bridge/hopper_bridge.py +6 -1
- package/dist/android/JadxConfiguration.js +87 -7
- package/dist/android/JadxMcpTransport.js +14 -2
- package/dist/android/JadxProvider.js +57 -35
- package/dist/application/BinaryTargetResolver.js +5 -3
- package/dist/application/BrowserEvidence.js +3 -8
- package/dist/application/BrowserScenarioEvidence.js +2 -18
- package/dist/application/CapabilityInventory.js +43 -9
- package/dist/application/ClientConfigurationDocument.js +69 -25
- package/dist/application/DirectAnalysis.js +29 -14
- package/dist/application/DirectAnalysisCleanup.js +72 -0
- package/dist/application/DirectAnalysisStatus.js +4 -5
- package/dist/application/Doctor.js +15 -19
- package/dist/application/DoctorDiagnostics.js +1 -2
- package/dist/application/EnhancedTools.js +51 -6
- package/dist/application/EvidenceBundleFiles.js +8 -3
- package/dist/application/InvestigationProviders.js +9 -1
- package/dist/application/JsonFiles.js +42 -9
- package/dist/application/LinuxHopper.js +9 -6
- package/dist/application/MacHopper.js +15 -18
- package/dist/application/RealHopperAssertions.js +0 -11
- package/dist/application/ReconstructionObligationCandidates.js +1 -1
- package/dist/application/ReferenceSourceImportEntries.js +1 -1
- package/dist/application/Setup.js +8 -16
- package/dist/application/SetupHost.js +16 -27
- package/dist/application/SetupPlan.js +6 -6
- package/dist/application/Uninstall.js +81 -29
- package/dist/application/UpdateMaintenance.js +7 -5
- package/dist/application/UpdateRuntime.js +12 -12
- package/dist/application/WebScriptExportService.js +30 -4
- package/dist/application/WorkflowEvidence.js +25 -2
- package/dist/application/XrefsAddressResolution.js +45 -0
- package/dist/application/analysisView/AnalysisViewService.js +76 -0
- package/dist/application/binary/AnalysisClientCleanup.js +30 -5
- package/dist/application/binary/AnalysisProviderEvaluation.js +1 -2
- package/dist/application/binary/AnalysisProviderRegistry.js +2 -6
- package/dist/application/binary/AnalysisSnapshotCache.js +10 -8
- package/dist/application/binary/BinarySession.js +70 -29
- package/dist/application/binary/BinarySessionComposition.js +1 -3
- package/dist/application/binary/BinarySessionExecution.js +3 -5
- package/dist/application/binary/BinarySessionOpen.js +1 -1
- package/dist/application/binary/BinarySessionRecords.js +1 -1
- package/dist/application/binary/BinarySessionStatus.js +1 -6
- package/dist/application/binary/CompositeProvider.js +4 -18
- package/dist/application/binary/LazyAnalysisProvider.js +5 -5
- package/dist/application/binary/SessionProviderRouter.js +27 -135
- package/dist/application/homebrew.js +48 -0
- package/dist/application/javascript/ElectronActiveEvidence.js +9 -13
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +2 -6
- package/dist/application/javascript/JavaScriptApplicationService.js +6 -1
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +5 -3
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +11 -9
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +11 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +9 -0
- package/dist/application/javascript/JavaScriptArtifactGraphDocuments.js +8 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +12 -3
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +0 -1
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +43 -16
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +46 -6
- package/dist/application/javascript/JavaScriptModuleRelationships.js +1 -1
- package/dist/application/javascript/JavaScriptRuntimeObservationService.js +3 -3
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -2
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +1 -5
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +75 -46
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +2 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +42 -19
- package/dist/application/managed/ManagedMemberComparisonService.js +2 -1
- package/dist/application/managed/ManagedNativeVerificationService.js +2 -1
- package/dist/application/process/ProcessCli.js +11 -11
- package/dist/application/process/ProcessEvidence.js +0 -1
- package/dist/artifacts/ArtifactProvider.js +39 -14
- package/dist/artifacts/ArtifactReader.js +31 -0
- package/dist/artifacts/DirectoryArtifactReader.js +2 -1
- package/dist/artifacts/MachOSliceArtifactReader.js +9 -2
- package/dist/artifacts/NativeDmgArtifactReader.js +65 -20
- package/dist/artifacts/SafeOutputTree.js +16 -2
- package/dist/artifacts/ZipArtifactReader.js +11 -4
- package/dist/artifacts/apple/AppleAssetCatalogAnalysis.js +4 -2
- package/dist/artifacts/apple/DylibResolutionReader.js +17 -7
- package/dist/artifacts/apple/KeyedArchiveReader.js +21 -3
- package/dist/artifacts/extraction/ArtifactExtraction.js +78 -21
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +67 -61
- package/dist/artifacts/inventory/ArtifactInventory.js +0 -1
- package/dist/artifacts/inventory/reader.js +3 -3
- package/dist/artifacts/inventory/scanCanonical.js +48 -24
- package/dist/artifacts/inventory/scanReader.js +5 -9
- package/dist/browser/BrowserScenarioPartialObservation.js +106 -0
- package/dist/browser/CdpBrowserProvider.js +2 -3
- package/dist/browser/CdpCaptureEventHandlers.js +2 -4
- package/dist/browser/CdpCaptureEvents.js +0 -1
- package/dist/browser/CdpCaptureValues.js +20 -0
- package/dist/browser/CdpElectronProvider.js +0 -2
- package/dist/browser/CdpElectronScriptEvents.js +2 -8
- package/dist/browser/CdpElectronScripts.js +2 -3
- package/dist/browser/CdpPageCaptureScripts.js +2 -3
- package/dist/browser/CdpSafeMetadata.js +10 -10
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +59 -44
- package/dist/browser/PlaywrightElectronActiveActions.js +2 -56
- package/dist/browser/PlaywrightElectronActiveProvider.js +10 -6
- package/dist/browser/PlaywrightScenarioArtifacts.js +1 -1
- package/dist/browser/PlaywrightScenarioBrowser.js +139 -39
- package/dist/browser/PlaywrightScenarioEvents.js +1 -1
- package/dist/browser/PlaywrightScenarioSession.js +39 -22
- package/dist/browser/assets/ScriptCaptureAdapters.js +1 -1
- package/dist/browser/history/CaptureFailures.js +6 -2
- package/dist/browser/history/MitmproxyCaptureAdapter.js +4 -2
- package/dist/catalogIdentity.js +0 -1
- package/dist/cli/analysisViewCommands.js +36 -0
- package/dist/cli/artifactCommands.js +11 -12
- package/dist/cli/coreAnalysisCommands.js +3 -3
- package/dist/cli/coreBinaryCommands.js +32 -27
- package/dist/cli/coreNativeCommands.js +9 -10
- package/dist/cli/electronCommands.js +4 -4
- package/dist/cli/interactiveSetup.js +6 -6
- package/dist/cli/managedCommands.js +7 -8
- package/dist/cli/nativeCallCommands.js +1 -2
- package/dist/cli/omittableDefaults.js +50 -0
- package/dist/cli/processCommands.js +3 -2
- package/dist/cli/setupCommands.js +16 -15
- package/dist/cli/utilityCommands.js +9 -9
- package/dist/cli.js +16 -8
- package/dist/cliBrowserScenarioCommands.js +2 -2
- package/dist/cliCommandNames.js +1 -0
- package/dist/cliJsonInput.js +15 -1
- package/dist/cliOutput.js +0 -38
- package/dist/composition/auxiliaryAnalysisProviders.js +27 -23
- package/dist/composition/binary.js +9 -9
- package/dist/composition/browserScenario.js +2 -1
- package/dist/composition/directAnalysis.js +20 -13
- package/dist/composition/electronScenario.js +1 -1
- package/dist/composition/optionalObservationProviders.js +12 -7
- package/dist/config/environment.js +6 -0
- package/dist/config/ghidraStartupTimeout.js +4 -9
- package/dist/config/homeDirectory.js +12 -0
- package/dist/config/mcpResponseBudget.js +9 -1
- package/dist/config/parseConfig.js +7 -3
- package/dist/config/parsers.js +19 -22
- package/dist/contracts/analysisViewToolContracts.js +56 -0
- package/dist/contracts/applicationToolContracts.js +5 -4
- package/dist/contracts/artifactComparisonExample.js +2 -2
- package/dist/contracts/artifactToolContracts.js +1 -1
- package/dist/contracts/browserScenarioToolContracts.js +1 -1
- package/dist/contracts/browserToolContracts.js +19 -15
- package/dist/contracts/enhancedInputs.js +2 -2
- package/dist/contracts/enhancedToolContracts.js +4 -3
- package/dist/contracts/evm/evmToolContracts.js +1 -1
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/inputSchemaPresentation.js +90 -0
- package/dist/contracts/investigationExamples.js +4 -3
- package/dist/contracts/javascript/electronToolContracts.js +1 -1
- package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +0 -20
- package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +245 -0
- package/dist/contracts/javascript/javascriptRuntimeObservationToolContracts.js +1 -1
- package/dist/contracts/managed/managedToolContracts.js +5 -10
- package/dist/contracts/managed/managedWorkflowToolContracts.js +1 -1
- package/dist/contracts/mobileApplicationGraphExamples.js +3 -3
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +1 -1
- package/dist/contracts/native/nativeToolContracts.js +2 -2
- package/dist/contracts/officialToolContracts.js +2 -1
- package/dist/contracts/promptContracts.js +2 -2
- package/dist/contracts/providerSelection.js +1 -1
- package/dist/contracts/sessionToolContracts.js +14 -2
- package/dist/contracts/sessionToolSchemas.js +1 -14
- package/dist/contracts/toolContracts.js +2 -0
- package/dist/contracts/toolEffects.js +1 -0
- package/dist/contracts/toolOutputSchemaGroups.js +136 -92
- package/dist/contracts/toolOutputSchemaPrimitives.js +11 -21
- package/dist/contracts/toolSchemaMetadata.js +18 -69
- package/dist/contracts/webNetworkCaptureToolContracts.js +1 -1
- package/dist/contracts/webRuntimeToolContracts.js +1 -1
- package/dist/contracts/webScriptToolContracts.js +1 -1
- package/dist/doctorRuntime.js +7 -5
- package/dist/domain/analysisErrorCore.js +3 -0
- package/dist/domain/analysisErrorPresentation.js +18 -3
- package/dist/domain/analysisErrorProjection.js +24 -5
- package/dist/domain/analysisSnapshot.js +29 -31
- package/dist/domain/analysisView/analysisView.js +243 -0
- package/dist/domain/analysisView/analysisViewCoverage.js +19 -0
- package/dist/domain/analysisView/binaryLayoutView.js +159 -0
- package/dist/domain/analysisView/javascriptApplicationView.js +238 -0
- package/dist/domain/android/androidApplication.js +1 -1
- package/dist/domain/apple/appleApplication.js +1 -1
- package/dist/domain/apple/dylibResolution.js +10 -3
- package/dist/domain/apple/interfaceBuilderGraph.js +0 -1
- package/dist/domain/apple/keyedArchive.js +26 -2
- package/dist/domain/artifactComparison.js +15 -6
- package/dist/domain/artifactGraph.js +16 -3
- package/dist/domain/artifactInventoryEvidence.js +9 -16
- package/dist/domain/artifactOperationError.js +3 -3
- package/dist/domain/artifactPartialObservation.js +1 -0
- package/dist/domain/artifactPathSyntax.js +49 -0
- package/dist/domain/binaryTarget.js +39 -13
- package/dist/domain/browserCaptureComparison.js +13 -49
- package/dist/domain/browserNetworkEvidence.js +10 -4
- package/dist/domain/browserObservation.js +0 -1
- package/dist/domain/browserObservationSchemas.js +14 -3
- package/dist/domain/browserScenario.js +0 -1
- package/dist/domain/browserScenarioCapture.js +1 -2
- package/dist/domain/browserScenarioDiff.js +0 -2
- package/dist/domain/browserScenarioDiffEvidence.js +0 -12
- package/dist/domain/browserScenarioDiffValues.js +2 -2
- package/dist/domain/browserScenarioValues.js +3 -4
- package/dist/domain/callPath.js +8 -9
- package/dist/domain/callPathSchemas.js +2 -2
- package/dist/domain/changedBehavior.js +3 -3
- package/dist/domain/completionLedgerGeneration.js +2 -1
- package/dist/domain/configurationErrors.js +12 -0
- package/dist/domain/conformancePackage.js +4 -3
- package/dist/domain/evidence.js +10 -36
- package/dist/domain/evidenceBundle.js +7 -9
- package/dist/domain/evidenceCompletionLedger.js +2 -1
- package/dist/domain/functionComparison.js +4 -5
- package/dist/domain/functionComparisonDimensions.js +120 -87
- package/dist/domain/functionComparisonNormalization.js +23 -34
- package/dist/domain/functionComparisonResults.js +1 -4
- package/dist/domain/functionComparisonSchemas.js +2 -8
- package/dist/domain/functionDossierEvidence.js +2 -37
- package/dist/domain/javascript/electronActiveObservation.js +26 -69
- package/dist/domain/javascript/electronObservation.js +14 -3
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +10 -9
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +2 -1
- package/dist/domain/javascript/electronStaticAnalysisNative.js +2 -1
- package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +2 -0
- package/dist/domain/javascript/javascriptApplicationGraph.js +26 -3
- package/dist/domain/javascript/javascriptApplicationGraphSchemas.js +9 -2
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +5 -2
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +2 -1
- package/dist/{application/javascript/JavaScriptReturnShapeProjection.js → domain/javascript/javascriptExportReturnShapeProjection.js} +4 -4
- package/dist/domain/javascript/javascriptExportShapeComparison.js +7 -1
- package/dist/domain/javascript/javascriptExportShapeComparisonIdentity.js +6 -1
- package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +29 -1
- package/dist/domain/javascript/javascriptExportShapeSelection.js +5 -5
- package/dist/domain/javascript/javascriptExportShapeVariants.js +67 -14
- package/dist/domain/javascript/javascriptFeatureSeed.js +20 -0
- package/dist/domain/javascript/javascriptFeatureTraversal.js +0 -1
- package/dist/domain/javascript/javascriptNativeHandoff.js +1 -1
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +0 -1
- package/dist/domain/javascript/javascriptRuntimeObservation.js +10 -2
- package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +1 -1
- package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +3 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +0 -1
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +9 -3
- package/dist/domain/javascript/javascriptSemanticAsyncEffects.js +2 -1
- package/dist/domain/javascript/javascriptSemanticCalls.js +2 -1
- package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -1
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +1 -1
- package/dist/domain/javascript/javascriptSemanticGraph.js +88 -46
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +77 -20
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +21 -27
- package/dist/domain/javascript/javascriptSemanticObjects.js +83 -42
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +1 -12
- package/dist/domain/javascript/javascriptSemanticProjection.js +2 -3
- package/dist/domain/javascript/javascriptSemanticPromises.js +2 -1
- package/dist/domain/javascript/javascriptSemanticResourceLimits.js +1 -1
- package/dist/domain/javascript/javascriptSemanticResources.js +1 -1
- package/dist/domain/javascript/javascriptSemanticReturns.js +32 -17
- package/dist/domain/javascript/javascriptSemanticSlots.js +72 -0
- package/dist/domain/javascript/javascriptSemanticValues.js +47 -54
- package/dist/domain/javascript/javascriptSourceMapPaths.js +104 -0
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +2 -1
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +0 -1
- package/dist/domain/javascript/sourceToBundleComparison.js +12 -3
- package/dist/domain/javascript/sourceToBundleSignals.js +47 -19
- package/dist/domain/localPath.js +1 -1
- package/dist/domain/managed/managedArtifact.js +6 -4
- package/dist/domain/managed/managedMemberComparison.js +2 -9
- package/dist/domain/managed/managedNativeVerification.js +0 -2
- package/dist/domain/managed/managedNativeVerificationMatch.js +9 -3
- package/dist/domain/native/binaryLayout.js +2 -3
- package/dist/domain/native/nativeApiBoundary.js +1 -1
- package/dist/domain/native/nativeCallObservation.js +5 -3
- package/dist/domain/native/nativeInstruction.js +7 -0
- package/dist/domain/native/recordedCrash.js +2 -3
- package/dist/domain/offsetDateTime.js +17 -0
- package/dist/domain/process/processCapture.js +13 -12
- package/dist/domain/process/processCaptureCoverage.js +67 -0
- package/dist/domain/process/processCaptureExample.js +2 -1
- package/dist/domain/process/processCaptureParsing.js +1 -34
- package/dist/domain/process/processCaptureValidation.js +81 -13
- package/dist/domain/process/processComparison.js +41 -22
- package/dist/domain/process/processObservation.js +10 -2
- package/dist/domain/process/processScenario.js +24 -2
- package/dist/domain/process/processTraceComparison.js +0 -2
- package/dist/domain/process/processTraceDimensionProjection.js +1 -1
- package/dist/domain/process/processTraceEvaluation.js +15 -11
- package/dist/domain/process/processTraceSpecification.js +3 -4
- package/dist/domain/providerAdapterError.js +2 -0
- package/dist/domain/reconstructionCoverage.js +5 -2
- package/dist/domain/reconstructionObligationLedgerSchemas.js +2 -1
- package/dist/domain/reconstructionReadinessSchemas.js +2 -1
- package/dist/domain/reconstructionVerification.js +3 -3
- package/dist/domain/reconstructionVerificationSchemas.js +2 -1
- package/dist/domain/referenceSourceGraph.js +20 -21
- package/dist/domain/staticRuntimeCorrelation.js +2 -2
- package/dist/domain/stringPatterns.js +6 -0
- package/dist/domain/swiftSymbolClassification.js +61 -0
- package/dist/domain/symbolAnalysis.js +66 -18
- package/dist/domain/webCaptureDiff.js +0 -1
- package/dist/domain/webCaptureDiffSchemas.js +6 -3
- package/dist/domain/webEventListeners.js +3 -2
- package/dist/domain/webExecution.js +3 -2
- package/dist/domain/webRuntime.js +0 -2
- package/dist/domain/webScriptExport.js +1 -1
- package/dist/dotnet/ManagedArtifactInspector.js +2 -19
- package/dist/dotnet/ManagedMemberInspector.js +12 -18
- package/dist/dotnet/ManagedMemberInspectorCore.js +47 -44
- package/dist/dotnet/ManagedMemberRows.js +75 -62
- package/dist/dotnet/ManagedMetadataInventory.js +16 -22
- package/dist/dotnet/ManagedMethodBodyReader.js +4 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +109 -94
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +12 -21
- package/dist/dotnet/ManagedReaderFailure.js +16 -0
- package/dist/dotnet/ManagedStaticProvider.js +3 -5
- package/dist/evaluation/AgentEvaluationFixtures.js +250 -0
- package/dist/evaluation/AgentEvaluationReport.js +28 -0
- package/dist/evaluation/CodexAgentEval.js +12 -8
- package/dist/evaluation/KnownAnswerEvaluation.js +281 -0
- package/dist/evm/EvmoleInterfaceProvider.js +2 -1
- package/dist/firmware/FirmwareCommand.js +9 -5
- package/dist/firmware/FirmwareProvider.js +4 -4
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +3 -6
- package/dist/ghidra/GhidraClient.js +91 -32
- package/dist/ghidra/GhidraClientStartup.js +0 -2
- package/dist/ghidra/GhidraDoctor.js +6 -5
- package/dist/ghidra/GhidraFunctionValues.js +3 -5
- package/dist/ghidra/GhidraInstallation.js +40 -12
- package/dist/ghidra/GhidraJavaLaunch.js +6 -2
- package/dist/ghidra/GhidraLauncher.js +15 -7
- package/dist/ghidra/GhidraProvider.js +6 -2
- package/dist/ghidra/GhidraProviderCapabilities.js +6 -0
- package/dist/ghidra/GhidraProviderClient.js +13 -3
- package/dist/ghidra/GhidraSessionError.js +2 -0
- package/dist/ghidra/GhidraSessionRoot.js +39 -0
- package/dist/ghidra/extensions/GhidraExtensions.js +17 -10
- package/dist/ghidra/extensions/nativeaot/NativeAotAdapter.js +8 -2
- package/dist/hopper/BridgeLauncher.js +34 -45
- package/dist/hopper/HopperAnalysisProfile.js +3 -8
- package/dist/hopper/HopperCleanup.js +56 -27
- package/dist/hopper/HopperClient.js +86 -65
- package/dist/hopper/HopperMachOImage.js +3 -2
- package/dist/hopper/HopperProvider.js +16 -18
- package/dist/hopper/HopperRegexSearch.js +3 -6
- package/dist/hopper/HopperTargetLease.js +132 -49
- package/dist/hopper/LinuxPrivateDisplayProbe.js +6 -0
- package/dist/ida/IdaConfiguration.js +8 -3
- package/dist/ida/IdaInput.js +1 -7
- package/dist/ida/IdaMcpConnection.js +8 -4
- package/dist/ida/IdaOperationRunner.js +3 -3
- package/dist/ida/IdaProvider.js +8 -12
- package/dist/ida/IdaSessionClient.js +20 -18
- package/dist/ida/IdaWorkspace.js +12 -13
- package/dist/inspector/V8InspectorCaptureProjection.js +1 -1
- package/dist/inspector/V8InspectorProvider.js +38 -28
- package/dist/javascript/recovery/WakaruCommand.js +7 -2
- package/dist/javascript/recovery/WakaruExecution.js +5 -2
- package/dist/main/shutdown.js +11 -3
- package/dist/main/startup.js +9 -2
- package/dist/main/transport.js +22 -2
- package/dist/main.js +11 -18
- package/dist/native/AppleMachoSelection.js +16 -6
- package/dist/native/CommandRunner.js +9 -7
- package/dist/native/LldbCallTracer.js +8 -2
- package/dist/native/NativeMacOSProvider.js +25 -15
- package/dist/native/NativeUiHelperRuntime.js +11 -2
- package/dist/native/NativeUiObservation.js +2 -2
- package/dist/native/pwntools/PwntoolsDecoder.js +2 -1
- package/dist/process/DarwinProcessRunTokenReader.js +16 -2
- package/dist/process/ExecFileOutput.js +88 -6
- package/dist/process/PrivateRuntimeRoot.js +10 -5
- package/dist/process/ProcessOwnership.js +1 -4
- package/dist/process/ProcessOwnershipObservation.js +11 -5
- package/dist/process/ProviderProcess.js +1 -3
- package/dist/process/capture/FilesystemSnapshot.js +50 -13
- package/dist/process/capture/ProcessCaptureError.js +13 -0
- package/dist/process/capture/ProcessCaptureLifecycle.js +158 -70
- package/dist/process/capture/ProcessFilesystemEffects.js +33 -3
- package/dist/process/capture/ProcessHarness.js +21 -25
- package/dist/process/capture/ProcessNormalization.js +20 -2
- package/dist/process/capture/ProcessSampling.js +25 -2
- package/dist/process/capture/TerminalRenderer.js +14 -0
- package/dist/process/snapshotEnvironment.js +14 -0
- package/dist/server/EvidenceMcpServer.js +25 -14
- package/dist/server/createServer.js +49 -36
- package/dist/server/mcpClientMetadata.js +12 -5
- package/dist/server/promptCompletion.js +3 -8
- package/dist/server/registerAnalysisViewTool.js +15 -0
- package/dist/server/registerAndroidTools.js +2 -3
- package/dist/server/registerApplicationTools/compareExportShapes.js +4 -5
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
- package/dist/server/registerApplicationTools/compareVersions.js +4 -5
- package/dist/server/registerApplicationTools/coverage.js +1 -2
- package/dist/server/registerApplicationTools/helpers.js +1 -2
- package/dist/server/registerApplicationTools/obligationLedger.js +4 -5
- package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -4
- package/dist/server/registerApplicationTools/traceFeature.js +4 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
- package/dist/server/registerArtifactComparisonTool.js +4 -5
- package/dist/server/registerBinaryDiagnosticsTools.js +2 -3
- package/dist/server/registerBrowserScenarioTool.js +3 -4
- package/dist/server/registerBrowserTools.js +13 -16
- package/dist/server/registerBundleComparisonTool.js +5 -6
- package/dist/server/registerCloseLifecycleTool.js +2 -3
- package/dist/server/registerElectronTools.js +10 -13
- package/dist/server/registerEnhancedTools.js +23 -23
- package/dist/server/registerEvidenceTools.js +3 -4
- package/dist/server/registerEvmTools.js +2 -3
- package/dist/server/registerFirmwareTools.js +2 -3
- package/dist/server/registerFunctionComparisonTool.js +7 -8
- package/dist/server/registerInvestigationTools.js +14 -15
- package/dist/server/registerJavaScriptRecoveryTool.js +2 -3
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +6 -6
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +5 -6
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +4 -5
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +6 -7
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +6 -7
- package/dist/server/registerOfficialTools.js +4 -19
- package/dist/server/registerProcessComparisonTool.js +8 -8
- package/dist/server/registerRecordedCrashTools.js +2 -3
- package/dist/server/registerSessionRecordTools.js +15 -19
- package/dist/server/registerSessionStatusTool.js +3 -4
- package/dist/server/registerSessionTools.js +12 -18
- package/dist/server/registerWebModuleTool.js +2 -3
- package/dist/server/registerWebNetworkCaptureTool.js +2 -3
- package/dist/server/registerWebRuntimeTools.js +4 -5
- package/dist/server/registerWebScriptTool.js +2 -3
- package/dist/server/registerWebSourceLocationTool.js +2 -3
- package/dist/server/toolResult.js +66 -94
- package/dist/server/toolResultEncoding.js +11 -10
- package/dist/windows/WindowsNativeLoader.js +1 -0
- package/dist/windows/WindowsOwnedProcess.js +60 -15
- package/dist/windows/WindowsPrivateRuntime.js +7 -8
- package/native/windows/README.md +3 -1
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +39 -30
- package/scripts/rea.mjs +3 -6
- package/skills/reverse-engineer-anything/SKILL.md +9 -8
- package/skills/reverse-engineer-anything/references/android-applications.md +6 -3
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -4
- package/skills/reverse-engineer-anything/references/javascript-applications.md +16 -6
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +9 -0
- package/dist/config.js +0 -1
- package/dist/contracts/browserCaptureToolInputSchema.js +0 -43
- package/dist/contracts/process/processCaptureExample.js +0 -2
- package/dist/contracts/toolOutputSchemas.js +0 -2
- package/dist/main/reload.js +0 -12
- package/dist/main/state.js +0 -3
- package/dist/server/sessionToolPolicies.js +0 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
2
|
import { lstat, open, opendir, realpath } from "node:fs/promises";
|
|
3
3
|
import { isAbsolute, join, relative, sep } from "node:path";
|
|
4
|
+
import { compareCodePoints } from "../domain/canonicalOrdering.js";
|
|
4
5
|
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
5
6
|
/** Deterministic, non-symlink-following directory reader. */
|
|
6
7
|
export class DirectoryArtifactReader {
|
|
@@ -38,7 +39,7 @@ export class DirectoryArtifactReader {
|
|
|
38
39
|
await handle.close().catch(() => undefined);
|
|
39
40
|
}
|
|
40
41
|
await withDirectoryIoContext("inspect directory", directory, () => assertContainedDirectory(root, directory));
|
|
41
|
-
children.sort(
|
|
42
|
+
children.sort(compareCodePoints);
|
|
42
43
|
const directories = [];
|
|
43
44
|
for (const name of children) {
|
|
44
45
|
abortIfNeeded(signal);
|
|
@@ -12,7 +12,7 @@ export class MachOSliceArtifactReader {
|
|
|
12
12
|
runner;
|
|
13
13
|
format = "file";
|
|
14
14
|
#command;
|
|
15
|
-
constructor(path, runner = new XcrunCommandRunner()) {
|
|
15
|
+
constructor(path, environment, runner = new XcrunCommandRunner(environment)) {
|
|
16
16
|
this.path = path;
|
|
17
17
|
this.runner = runner;
|
|
18
18
|
}
|
|
@@ -175,7 +175,7 @@ const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
|
|
|
175
175
|
reported.cpu_type_code !== null ||
|
|
176
176
|
reported.cpu_subtype_code !== null;
|
|
177
177
|
return ((hasPhysicalIdentity || structurallyUnique) &&
|
|
178
|
-
reported.name
|
|
178
|
+
lipoNameMatches(reported.name, observed.architecture) &&
|
|
179
179
|
(reported.file_offset === null ||
|
|
180
180
|
reported.file_offset === observed.slice_offset) &&
|
|
181
181
|
(reported.size === null || reported.size === observed.slice_size) &&
|
|
@@ -187,6 +187,13 @@ const lipoMatchesSlice = (reported, observed, structurallyUnique) => {
|
|
|
187
187
|
observed.fat_alignment_exponent === null ||
|
|
188
188
|
reported.alignment === 2 ** observed.fat_alignment_exponent));
|
|
189
189
|
};
|
|
190
|
+
/**
|
|
191
|
+
* Newer lipo names an arm64e ABI variant `arm64e.<variant>` (for example
|
|
192
|
+
* `arm64e.v1` for pointer-auth ABI version 1). The FAT table names that slice
|
|
193
|
+
* `arm64e`; its physical identity is still compared field by field.
|
|
194
|
+
*/
|
|
195
|
+
const lipoNameMatches = (reported, observed) => reported === observed ||
|
|
196
|
+
(observed === "arm64e" && /^arm64e\.[A-Za-z0-9_]+$/u.test(reported));
|
|
190
197
|
const parseSliceKeyInteger = (value) => {
|
|
191
198
|
if (value === undefined || !/^\d+$/u.test(value))
|
|
192
199
|
return null;
|
|
@@ -7,6 +7,13 @@ import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
|
7
7
|
import { DirectoryArtifactReader } from "./DirectoryArtifactReader.js";
|
|
8
8
|
import { execFileOutput } from "../process/ExecFileOutput.js";
|
|
9
9
|
const DETACH_TIMEOUT_MS = 120_000;
|
|
10
|
+
/**
|
|
11
|
+
* Waits before rechecking devices whose detach failed. A related device's
|
|
12
|
+
* later detach can eject one, `hdiutil info` can still list an ejected device
|
|
13
|
+
* briefly, and a volume can report busy just after it was read.
|
|
14
|
+
*/
|
|
15
|
+
const DETACH_SETTLE_DELAYS_MS = [250, 500, 1000];
|
|
16
|
+
const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
10
17
|
const attachOutputSchema = z.object({
|
|
11
18
|
"system-entities": z.array(z.object({
|
|
12
19
|
"dev-entry": z.string().startsWith("/dev/"),
|
|
@@ -18,10 +25,12 @@ const infoOutputSchema = z.object({
|
|
|
18
25
|
"system-entities": z.array(z.object({ "dev-entry": z.string() })),
|
|
19
26
|
})),
|
|
20
27
|
});
|
|
21
|
-
const
|
|
28
|
+
const createSystemHost = (environment) => ({
|
|
29
|
+
delay,
|
|
22
30
|
async run(arguments_, signal, options) {
|
|
23
31
|
try {
|
|
24
32
|
const { stdout, stderr } = await execFileOutput("/usr/bin/hdiutil", [...arguments_], {
|
|
33
|
+
env: environment,
|
|
25
34
|
...(options === undefined ? {} : { timeout: options.timeoutMs }),
|
|
26
35
|
...(signal === undefined ? {} : { signal }),
|
|
27
36
|
});
|
|
@@ -41,7 +50,7 @@ const systemHost = {
|
|
|
41
50
|
throw new ArtifactReaderFailure(commandFailureReason(cause, arguments_[0]), `hdiutil ${arguments_[0] ?? "operation"} failed: ${describeCommandFailure(cause, arguments_)}`, { cause });
|
|
42
51
|
}
|
|
43
52
|
},
|
|
44
|
-
};
|
|
53
|
+
});
|
|
45
54
|
/** Read-only macOS DMG adapter that owns attachment and reverse-order detach. */
|
|
46
55
|
export class NativeDmgArtifactReader {
|
|
47
56
|
path;
|
|
@@ -56,10 +65,10 @@ export class NativeDmgArtifactReader {
|
|
|
56
65
|
this.host = host;
|
|
57
66
|
}
|
|
58
67
|
/** Verify and attach one image beneath an exclusively owned temporary root. */
|
|
59
|
-
static async create(path, signal, host
|
|
60
|
-
if (process.platform !== "darwin" && host ===
|
|
68
|
+
static async create(path, environment, signal, host) {
|
|
69
|
+
if (process.platform !== "darwin" && host === undefined)
|
|
61
70
|
throw new ArtifactReaderFailure("unavailable", "Native DMG traversal is available only on macOS");
|
|
62
|
-
const reader = new NativeDmgArtifactReader(path, host);
|
|
71
|
+
const reader = new NativeDmgArtifactReader(path, host ?? createSystemHost(environment));
|
|
63
72
|
await reader.attach(signal);
|
|
64
73
|
return reader;
|
|
65
74
|
}
|
|
@@ -80,24 +89,36 @@ export class NativeDmgArtifactReader {
|
|
|
80
89
|
}
|
|
81
90
|
async close() {
|
|
82
91
|
let detachFailure;
|
|
83
|
-
|
|
92
|
+
let remainingDevices = [];
|
|
84
93
|
for (const device of [...this.#devices].reverse()) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.#provenance.push(command(["detach", device], ["mount"]));
|
|
94
|
+
const failure = await this.#detach(device);
|
|
95
|
+
if (failure !== undefined) {
|
|
96
|
+
remainingDevices.push(device);
|
|
97
|
+
detachFailure ??= failure;
|
|
90
98
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
}
|
|
100
|
+
// Detaching a synthesized APFS container also ejects the image that backs
|
|
101
|
+
// it, so a device whose own detach failed may be gone by the end of the
|
|
102
|
+
// pass, and hdiutil can list an ejected device or report busy briefly.
|
|
103
|
+
// Only a device that stays attached through every recheck is a failure.
|
|
104
|
+
for (const delayMs of DETACH_SETTLE_DELAYS_MS) {
|
|
105
|
+
if (remainingDevices.length === 0)
|
|
106
|
+
break;
|
|
107
|
+
await (this.host.delay ?? delay)(delayMs);
|
|
108
|
+
const stillAttached = [];
|
|
109
|
+
for (const device of remainingDevices) {
|
|
110
|
+
if (!(await this.#isAttached(device)))
|
|
111
|
+
continue;
|
|
112
|
+
const failure = await this.#detach(device);
|
|
113
|
+
if (failure !== undefined) {
|
|
114
|
+
stillAttached.push(device);
|
|
115
|
+
detachFailure = failure;
|
|
98
116
|
}
|
|
99
117
|
}
|
|
118
|
+
remainingDevices = stillAttached;
|
|
100
119
|
}
|
|
120
|
+
if (remainingDevices.length === 0)
|
|
121
|
+
detachFailure = undefined;
|
|
101
122
|
this.#devices = remainingDevices.reverse();
|
|
102
123
|
if (this.#devices.length === 0 && this.#mountRoot !== undefined)
|
|
103
124
|
await rm(this.#mountRoot, { recursive: true, force: true }).then(() => {
|
|
@@ -107,7 +128,31 @@ export class NativeDmgArtifactReader {
|
|
|
107
128
|
detachFailure ??= cause;
|
|
108
129
|
});
|
|
109
130
|
if (detachFailure !== undefined)
|
|
110
|
-
throw new ArtifactReaderFailure("unavailable", `DMG detach or mount-root cleanup failed for ${JSON.stringify(this.path)}: ${failureMessage(detachFailure)}`, {
|
|
131
|
+
throw new ArtifactReaderFailure("unavailable", `DMG detach or mount-root cleanup failed for ${JSON.stringify(this.path)}: ${failureMessage(detachFailure)}`, {
|
|
132
|
+
cause: detachFailure,
|
|
133
|
+
cleanup: {
|
|
134
|
+
reason: failureMessage(detachFailure),
|
|
135
|
+
resources: [
|
|
136
|
+
...this.#devices.map((device) => `DMG device ${device}`),
|
|
137
|
+
...(this.#mountRoot === undefined
|
|
138
|
+
? []
|
|
139
|
+
: [`DMG mount root ${this.#mountRoot}`]),
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/** Detach one device; return the failure only while it remains attached. */
|
|
145
|
+
async #detach(device) {
|
|
146
|
+
try {
|
|
147
|
+
await runChecked(this.host, ["detach", device], undefined, {
|
|
148
|
+
timeoutMs: DETACH_TIMEOUT_MS,
|
|
149
|
+
});
|
|
150
|
+
this.#provenance.push(command(["detach", device], ["mount"]));
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
catch (cause) {
|
|
154
|
+
return (await this.#isAttached(device)) ? cause : undefined;
|
|
155
|
+
}
|
|
111
156
|
}
|
|
112
157
|
/**
|
|
113
158
|
* Report whether hdiutil still lists a device; unknown state counts as
|
|
@@ -175,7 +220,7 @@ export class NativeDmgArtifactReader {
|
|
|
175
220
|
cleanupFailure = cleanupCause;
|
|
176
221
|
}
|
|
177
222
|
if (cleanupFailure !== undefined)
|
|
178
|
-
throw
|
|
223
|
+
throw ArtifactReaderFailure.withCleanup(cause, ArtifactReaderFailure.cleanupObservation(cleanupFailure, `DMG mount root ${this.#mountRoot ?? this.path}`));
|
|
179
224
|
throw cause;
|
|
180
225
|
}
|
|
181
226
|
}
|
|
@@ -129,7 +129,13 @@ export class SafeOutputTree {
|
|
|
129
129
|
async rollback() {
|
|
130
130
|
if (this.#published)
|
|
131
131
|
return structuredClone(this.#cleanup);
|
|
132
|
-
|
|
132
|
+
let removalFailure;
|
|
133
|
+
try {
|
|
134
|
+
await rm(this.#outputRoot, { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
catch (cause) {
|
|
137
|
+
removalFailure = cause;
|
|
138
|
+
}
|
|
133
139
|
const absent = await isAbsent(this.#outputRoot);
|
|
134
140
|
this.#cleanup = absent
|
|
135
141
|
? { status: "complete", residualPaths: [] }
|
|
@@ -138,7 +144,15 @@ export class SafeOutputTree {
|
|
|
138
144
|
residualPaths: [basename(this.#outputRoot)],
|
|
139
145
|
};
|
|
140
146
|
if (!absent)
|
|
141
|
-
throw new ArtifactReaderFailure("integrity",
|
|
147
|
+
throw new ArtifactReaderFailure("integrity", `Extraction output cleanup could not be verified${removalFailure === undefined ? "" : `: ${removalFailure instanceof Error ? removalFailure.message : String(removalFailure)}`}`, {
|
|
148
|
+
cause: removalFailure,
|
|
149
|
+
cleanup: {
|
|
150
|
+
reason: removalFailure instanceof Error
|
|
151
|
+
? removalFailure.message
|
|
152
|
+
: "Extraction output root remains after rollback",
|
|
153
|
+
resources: [this.#outputRoot],
|
|
154
|
+
},
|
|
155
|
+
});
|
|
142
156
|
return structuredClone(this.#cleanup);
|
|
143
157
|
}
|
|
144
158
|
async #prepareParent(relativePath) {
|
|
@@ -5,10 +5,12 @@ import { Reader, ZipReader } from "@zip.js/zip.js";
|
|
|
5
5
|
import { ArtifactReaderFailure, } from "./ArtifactReader.js";
|
|
6
6
|
class NodeFileReader extends Reader {
|
|
7
7
|
path;
|
|
8
|
+
maximumReadBytes;
|
|
8
9
|
#handle;
|
|
9
|
-
constructor(path) {
|
|
10
|
+
constructor(path, maximumReadBytes) {
|
|
10
11
|
super(path);
|
|
11
12
|
this.path = path;
|
|
13
|
+
this.maximumReadBytes = maximumReadBytes;
|
|
12
14
|
}
|
|
13
15
|
async init() {
|
|
14
16
|
this.#handle = await open(this.path, "r");
|
|
@@ -18,7 +20,11 @@ class NodeFileReader extends Reader {
|
|
|
18
20
|
const handle = this.#handle;
|
|
19
21
|
if (handle === undefined)
|
|
20
22
|
throw new Error("ZIP reader is not initialized");
|
|
21
|
-
const
|
|
23
|
+
const readBytes = Math.min(length, this.size - index);
|
|
24
|
+
if (this.maximumReadBytes !== undefined &&
|
|
25
|
+
readBytes > this.maximumReadBytes)
|
|
26
|
+
throw new ArtifactReaderFailure("limit", `ZIP metadata read requires ${readBytes} bytes, exceeding the ${this.maximumReadBytes}-byte read budget`);
|
|
27
|
+
const bytes = Buffer.alloc(readBytes);
|
|
22
28
|
const read = await handle.read(bytes, 0, bytes.length, index);
|
|
23
29
|
return bytes.subarray(0, read.bytesRead);
|
|
24
30
|
}
|
|
@@ -33,9 +39,10 @@ export class ZipArtifactReader {
|
|
|
33
39
|
#source;
|
|
34
40
|
#reader;
|
|
35
41
|
#entries = new Map();
|
|
36
|
-
|
|
42
|
+
/** Optionally bound each metadata read before allocating its backing buffer. */
|
|
43
|
+
constructor(path, format, maximumMetadataReadBytes) {
|
|
37
44
|
this.format = format;
|
|
38
|
-
this.#source = new NodeFileReader(path);
|
|
45
|
+
this.#source = new NodeFileReader(path, maximumMetadataReadBytes);
|
|
39
46
|
this.#reader = new ZipReader(this.#source, {
|
|
40
47
|
checkSignature: true,
|
|
41
48
|
checkOverlappingEntry: true,
|
|
@@ -39,7 +39,8 @@ export const analyzeAppleAssetCatalogs = async (input) => {
|
|
|
39
39
|
const inspected = await inspectAssetCatalogEntry({
|
|
40
40
|
reader,
|
|
41
41
|
entry,
|
|
42
|
-
runAssetUtil: input.runAssetUtil ??
|
|
42
|
+
runAssetUtil: input.runAssetUtil ??
|
|
43
|
+
((path, signal) => runAssetUtil(path, input.environment, signal)),
|
|
43
44
|
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
44
45
|
});
|
|
45
46
|
totalMetadataBytes += inspected.metadataBytes;
|
|
@@ -150,9 +151,10 @@ export const collectInterfaceBuilderResourceKeys = (nodes) => nodes.flatMap((nod
|
|
|
150
151
|
]
|
|
151
152
|
: []);
|
|
152
153
|
});
|
|
153
|
-
const runAssetUtil = async (path, signal) => {
|
|
154
|
+
const runAssetUtil = async (path, environment, signal) => {
|
|
154
155
|
try {
|
|
155
156
|
return (await execFileOutput(ASSETUTIL, ["--info", path], {
|
|
157
|
+
env: environment,
|
|
156
158
|
timeout: 60_000,
|
|
157
159
|
maxBuffer: MAX_CATALOG_BYTES,
|
|
158
160
|
...(signal === undefined ? {} : { signal }),
|
|
@@ -2,11 +2,14 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import { lstat, open, readlink, realpath } from "node:fs/promises";
|
|
4
4
|
import { join, relative, sep } from "node:path";
|
|
5
|
+
import { AnalysisInputError } from "../../domain/analysisErrorCore.js";
|
|
5
6
|
import { resolveTreePath } from "../../domain/apple/dyldPaths.js";
|
|
6
7
|
import { dylibResolutionInputSchema, dylibResolutionResultSchema, traceDylibLoading, } from "../../domain/apple/dylibResolution.js";
|
|
8
|
+
import { projectInputIssues } from "../../domain/inputIssueProjection.js";
|
|
7
9
|
import { ArtifactReaderFailure } from "../ArtifactReader.js";
|
|
8
10
|
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
|
9
11
|
import { hasMachoMagic, readMachoImage } from "./MachoLoadCommandReader.js";
|
|
12
|
+
const OPERATION = "trace_dylib_resolution";
|
|
10
13
|
const HASH_CHUNK_BYTES = 1024 * 1024;
|
|
11
14
|
/** Lazily probed, symlink-preserving view of one analyzed directory. */
|
|
12
15
|
class FilesystemTreeView {
|
|
@@ -64,7 +67,7 @@ class FilesystemTreeView {
|
|
|
64
67
|
export const traceDylibResolution = async (options) => {
|
|
65
68
|
const parsed = dylibResolutionInputSchema.safeParse(options.parameters);
|
|
66
69
|
if (!parsed.success)
|
|
67
|
-
throw new
|
|
70
|
+
throw new AnalysisInputError(OPERATION, { cause: parsed.error }, projectInputIssues(parsed.error.issues, options.parameters));
|
|
68
71
|
// Canonicalization is inside the translated region: a revoked permission
|
|
69
72
|
// keeps its reason and path.
|
|
70
73
|
let root = options.rootPath;
|
|
@@ -79,7 +82,7 @@ export const traceDylibResolution = async (options) => {
|
|
|
79
82
|
: options.enumerateRoots
|
|
80
83
|
? await executableRoots(root, view, options.signal)
|
|
81
84
|
: { roots: [target], unclassified: [] };
|
|
82
|
-
const roots = await requireMachoRoots(view, requested);
|
|
85
|
+
const roots = await requireMachoRoots(view, requested, parsed.data.roots !== undefined);
|
|
83
86
|
const trace = await traceDylibLoading(view, {
|
|
84
87
|
roots,
|
|
85
88
|
unclassified,
|
|
@@ -151,17 +154,24 @@ const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
|
151
154
|
/**
|
|
152
155
|
* Resolve each root segment by segment, as dependency candidates are, so a
|
|
153
156
|
* symlink in an intermediate directory cannot lead outside the analyzed root.
|
|
157
|
+
* A root the caller selected that fails is an input error on that root; a
|
|
158
|
+
* root REA derived itself keeps reporting an artifact failure.
|
|
154
159
|
*/
|
|
155
|
-
const requireMachoRoots = async (view, roots) => {
|
|
160
|
+
const requireMachoRoots = async (view, roots, callerSelected) => {
|
|
156
161
|
const resolved = [];
|
|
157
|
-
for (const path of roots) {
|
|
162
|
+
for (const [index, path] of roots.entries()) {
|
|
163
|
+
const reject = (reason, message) => callerSelected
|
|
164
|
+
? new AnalysisInputError(OPERATION, undefined, [
|
|
165
|
+
{ path: ["roots", index], reason: "invalid_value", message },
|
|
166
|
+
])
|
|
167
|
+
: new ArtifactReaderFailure(reason, message);
|
|
158
168
|
const lookup = await resolveTreePath(view, path);
|
|
159
169
|
if (lookup.kind === "escapes")
|
|
160
|
-
throw
|
|
170
|
+
throw reject("path", `Root ${path} resolves outside the analyzed root`);
|
|
161
171
|
if (lookup.kind !== "file")
|
|
162
|
-
throw
|
|
172
|
+
throw reject("path", `Root ${path} is not a regular file in the analyzed root`);
|
|
163
173
|
if ((await view.image(lookup.path)).status === "not-mach-o")
|
|
164
|
-
throw
|
|
174
|
+
throw reject("format", `Root ${path} is not a Mach-O image`);
|
|
165
175
|
if (!resolved.includes(lookup.path))
|
|
166
176
|
resolved.push(lookup.path);
|
|
167
177
|
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import { join } from "node:path";
|
|
2
3
|
import { parseBinary } from "plist";
|
|
3
4
|
import { z } from "zod";
|
|
4
|
-
import { AnalysisInputError } from "../../domain/analysisErrorCore.js";
|
|
5
|
+
import { AnalysisInputError, AnalysisUnsupportedTargetError, } from "../../domain/analysisErrorCore.js";
|
|
5
6
|
import { projectPlistValue } from "../../domain/apple/plistValue.js";
|
|
6
7
|
import { createPlistNumberProjection } from "../../domain/apple/plistNumbers.js";
|
|
7
8
|
import { binaryPlistNumberLiterals, xmlPlistNumberLiterals, } from "./PlistNumberLiterals.js";
|
|
8
9
|
import { omittedPrototypeKeysLimitation, parseXmlPropertyList, } from "../../domain/propertyListKeys.js";
|
|
9
|
-
import { keyedArchiveInputSchema, keyedArchiveResultSchema, projectKeyedArchive, } from "../../domain/apple/keyedArchive.js";
|
|
10
|
+
import { KeyedArchiveKindError, keyedArchiveInputSchema, keyedArchiveResultSchema, projectKeyedArchive, } from "../../domain/apple/keyedArchive.js";
|
|
10
11
|
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
|
11
12
|
import { ArtifactReaderFailure } from "../ArtifactReader.js";
|
|
12
13
|
import { decodeXmlPlistText } from "../../domain/propertyListXmlText.js";
|
|
@@ -16,7 +17,7 @@ export const decodeKeyedArchiveBytes = (bytes, selection) => {
|
|
|
16
17
|
if (bytes.length > MAX_BYTES)
|
|
17
18
|
throw new RangeError("Keyed archive exceeds 64 MiB");
|
|
18
19
|
if (bytes.subarray(0, 10).toString("ascii") === "NIBArchive")
|
|
19
|
-
throw new
|
|
20
|
+
throw new KeyedArchiveKindError("Selected file is a compiled NIBArchive, not a Foundation plist archive; decode it with decode_interface_builder", "nib-archive");
|
|
20
21
|
const binary = bytes.subarray(0, 8).toString("ascii") === "bplist00";
|
|
21
22
|
const xmlText = binary ? undefined : decodeXmlPlistText(bytes);
|
|
22
23
|
const parsed = binary
|
|
@@ -56,6 +57,17 @@ const normalizePlist = (value) => {
|
|
|
56
57
|
throw new RangeError("Keyed archive contains a non-finite real");
|
|
57
58
|
return projected.value;
|
|
58
59
|
};
|
|
60
|
+
/**
|
|
61
|
+
* Point to the workflow that reads the selected kind of file on this host.
|
|
62
|
+
* decode_interface_builder is portable; inspect_plist requires macOS.
|
|
63
|
+
*/
|
|
64
|
+
const keyedArchiveKindRemediation = (kind, platform) => {
|
|
65
|
+
if (kind === "nib-archive")
|
|
66
|
+
return "Decode compiled NIBArchive files with decode_interface_builder on the app bundle.";
|
|
67
|
+
return platform === "darwin"
|
|
68
|
+
? "Inspect an ordinary property list with inspect_plist; inspect_keyed_archive decodes NSKeyedArchiver archives only."
|
|
69
|
+
: "Select an NSKeyedArchiver archive; inspect_keyed_archive decodes only those. inspect_plist, which reads ordinary property lists, requires a macOS host.";
|
|
70
|
+
};
|
|
59
71
|
/** Read exactly one regular, contained bundle entry without following symlinks. */
|
|
60
72
|
export const inspectBundleKeyedArchive = async (input) => {
|
|
61
73
|
const selected = keyedArchiveInputSchema.parse(input.parameters);
|
|
@@ -103,6 +115,12 @@ export const inspectBundleKeyedArchive = async (input) => {
|
|
|
103
115
|
catch (cause) {
|
|
104
116
|
if (cause instanceof AnalysisInputError)
|
|
105
117
|
throw cause;
|
|
118
|
+
// An intact file of another kind is not a damaged archive.
|
|
119
|
+
if (cause instanceof KeyedArchiveKindError)
|
|
120
|
+
throw new AnalysisUnsupportedTargetError("inspect_keyed_archive", join(input.bundlePath, entry.path), cause.message, {
|
|
121
|
+
cause,
|
|
122
|
+
remediationAction: keyedArchiveKindRemediation(cause.kind, input.platform ?? process.platform),
|
|
123
|
+
});
|
|
106
124
|
throw new ArtifactReaderFailure(cause instanceof RangeError ? "limit" : "format", `Cannot decode selected Foundation keyed archive: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
107
125
|
}
|
|
108
126
|
}
|
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
import { lstat, realpath } from "node:fs/promises";
|
|
2
|
+
import { compareCodePoints } from "../../domain/canonicalOrdering.js";
|
|
2
3
|
import { canonicalDigest } from "../../domain/comparisonSemantics.js";
|
|
3
4
|
import { AsarArtifactReader } from "../AsarArtifactReader.js";
|
|
4
5
|
import { ArtifactPathRegistry, normalizeArtifactPath, } from "../ArtifactPaths.js";
|
|
5
6
|
import { ArtifactReaderFailure, } from "../ArtifactReader.js";
|
|
7
|
+
import { abortIfNeeded } from "../ArtifactHash.js";
|
|
6
8
|
import { DirectoryArtifactReader } from "../DirectoryArtifactReader.js";
|
|
7
9
|
import { SafeOutputTree } from "../SafeOutputTree.js";
|
|
8
10
|
import { ZipArtifactReader } from "../ZipArtifactReader.js";
|
|
9
11
|
import { MachOSliceArtifactReader } from "../MachOSliceArtifactReader.js";
|
|
10
12
|
import { artifactExtractionResultSchema, } from "../../domain/artifactGraph.js";
|
|
13
|
+
import { AnalysisUnsupportedTargetError } from "../../domain/analysisErrorCore.js";
|
|
11
14
|
import { scanArtifactInventory } from "../inventory/ArtifactInventory.js";
|
|
12
15
|
/** Extract every regular inventory occurrence into an exclusively owned absent root. */
|
|
13
16
|
export const extractArtifact = async (input, signal) => {
|
|
17
|
+
// Cancellation wins over every later refusal, including unsupported formats.
|
|
18
|
+
abortIfNeeded(signal);
|
|
14
19
|
const sourcePath = await realpath(input.inputPath);
|
|
20
|
+
await requireExtractableFormat(sourcePath, input);
|
|
15
21
|
const snapshot = await scanArtifactInventory(sourcePath, {
|
|
16
22
|
signal,
|
|
23
|
+
environment: input.environment,
|
|
17
24
|
});
|
|
18
25
|
const selectedOccurrences = snapshot.occurrences.filter((occurrence) => (occurrence.entry_kind === "file" || occurrence.entry_kind === "slice") &&
|
|
19
26
|
occurrence.logical_path !== ".");
|
|
@@ -29,11 +36,14 @@ export const extractArtifact = async (input, signal) => {
|
|
|
29
36
|
nodes,
|
|
30
37
|
};
|
|
31
38
|
const selected = selectedOccurrences.map((occurrence) => {
|
|
39
|
+
// REA never decrypts archive entries, so an encrypted entry makes the
|
|
40
|
+
// complete extraction unsupported rather than the archive invalid.
|
|
41
|
+
if (occurrence.encrypted)
|
|
42
|
+
throw new AnalysisUnsupportedTargetError("extract_artifact", input.inputPath, `Archive entry ${occurrence.logical_path} is encrypted; REA does not decrypt archive entries, so the archive cannot be extracted completely`);
|
|
32
43
|
if ((occurrence.entry_kind !== "file" && occurrence.entry_kind !== "slice") ||
|
|
33
44
|
occurrence.artifact_id === null ||
|
|
34
|
-
occurrence.encrypted ||
|
|
35
45
|
occurrence.logical_path === ".")
|
|
36
|
-
throw new ArtifactReaderFailure("format", `Selected occurrence is not an extractable regular child file: ${occurrence.occurrence_id}`);
|
|
46
|
+
throw new ArtifactReaderFailure("format", `Selected occurrence is not an extractable regular child file: ${occurrence.logical_path} (${occurrence.occurrence_id})`);
|
|
37
47
|
const node = inventory.nodes.get(occurrence.artifact_id);
|
|
38
48
|
if (node === undefined)
|
|
39
49
|
throw new ArtifactReaderFailure("integrity", `Selected occurrence has no inventory node: ${occurrence.occurrence_id}`);
|
|
@@ -49,11 +59,13 @@ export const extractArtifact = async (input, signal) => {
|
|
|
49
59
|
};
|
|
50
60
|
const materializeSelection = async ({ input, sourcePath, inventory, selected, signal, }) => {
|
|
51
61
|
const byPath = new Map(selected.map((item) => [item.occurrence.logical_path, item]));
|
|
52
|
-
const reader = await createReader(sourcePath, input
|
|
53
|
-
|
|
62
|
+
const reader = await createReader(sourcePath, input);
|
|
63
|
+
let output;
|
|
64
|
+
let readerCloseAttempted = false;
|
|
54
65
|
let readerClosed = false;
|
|
55
66
|
const extracted = [];
|
|
56
67
|
try {
|
|
68
|
+
output = await SafeOutputTree.create(input.outputRoot);
|
|
57
69
|
const materialized = [];
|
|
58
70
|
const registry = new ArtifactPathRegistry();
|
|
59
71
|
for await (const entry of reader.entries(signal)) {
|
|
@@ -77,20 +89,53 @@ const materializeSelection = async ({ input, sourcePath, inventory, selected, si
|
|
|
77
89
|
});
|
|
78
90
|
materialized.push(selectedItem);
|
|
79
91
|
}
|
|
92
|
+
readerCloseAttempted = true;
|
|
80
93
|
await reader.close();
|
|
81
94
|
readerClosed = true;
|
|
82
|
-
extracted.sort((left, right) => left.relative_path
|
|
95
|
+
extracted.sort((left, right) => compareCodePoints(left.relative_path, right.relative_path));
|
|
83
96
|
const result = createExtractionResult(input, inventory, materialized, extracted);
|
|
84
97
|
await output.commit();
|
|
85
98
|
return result;
|
|
86
99
|
}
|
|
87
100
|
catch (cause) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
const cleanupFailures = [];
|
|
102
|
+
if (readerCloseAttempted && !readerClosed)
|
|
103
|
+
cleanupFailures.push({
|
|
104
|
+
cause,
|
|
105
|
+
resource: `artifact reader for ${sourcePath}`,
|
|
92
106
|
});
|
|
93
|
-
|
|
107
|
+
if (!readerCloseAttempted) {
|
|
108
|
+
try {
|
|
109
|
+
readerCloseAttempted = true;
|
|
110
|
+
await reader.close();
|
|
111
|
+
}
|
|
112
|
+
catch (cleanupCause) {
|
|
113
|
+
cleanupFailures.push({
|
|
114
|
+
cause: cleanupCause,
|
|
115
|
+
resource: `artifact reader for ${sourcePath}`,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (output !== undefined) {
|
|
120
|
+
try {
|
|
121
|
+
await output.rollback();
|
|
122
|
+
}
|
|
123
|
+
catch (cleanupCause) {
|
|
124
|
+
cleanupFailures.push({
|
|
125
|
+
cause: cleanupCause,
|
|
126
|
+
resource: input.outputRoot,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (cleanupFailures.length > 0) {
|
|
131
|
+
const observations = cleanupFailures.map(({ cause: cleanupCause, resource }) => ArtifactReaderFailure.cleanupObservation(cleanupCause, resource));
|
|
132
|
+
throw ArtifactReaderFailure.withCleanup(cause, {
|
|
133
|
+
reason: observations.map(({ reason }) => reason).join("; "),
|
|
134
|
+
resources: [
|
|
135
|
+
...new Set(observations.flatMap(({ resources }) => resources)),
|
|
136
|
+
],
|
|
137
|
+
});
|
|
138
|
+
}
|
|
94
139
|
throw cause;
|
|
95
140
|
}
|
|
96
141
|
};
|
|
@@ -99,7 +144,7 @@ const createExtractionResult = (input, inventory, selected, extracted) => {
|
|
|
99
144
|
source_manifest_id: inventory.manifest.manifest_id,
|
|
100
145
|
selected_occurrence_ids: selected
|
|
101
146
|
.map(({ occurrence }) => occurrence.occurrence_id)
|
|
102
|
-
.sort(
|
|
147
|
+
.sort(compareCodePoints),
|
|
103
148
|
files_sha256: canonicalDigest(extracted, "Artifact"),
|
|
104
149
|
output_root_alias: "$OUTPUT_ROOT",
|
|
105
150
|
};
|
|
@@ -133,20 +178,32 @@ const collectNodes = (items, selected, output) => {
|
|
|
133
178
|
if (selected.has(item.artifact_id))
|
|
134
179
|
output.set(item.artifact_id, item);
|
|
135
180
|
};
|
|
136
|
-
const
|
|
137
|
-
|
|
181
|
+
const ZIP_FORMATS = ["ipa", "apk", "msix", "appx", "zip"];
|
|
182
|
+
const isZipFormat = (format) => ZIP_FORMATS.includes(format);
|
|
183
|
+
/**
|
|
184
|
+
* Refuse a format without an extraction reader before inventory work starts.
|
|
185
|
+
* The target kind, not the host, is unsupported by extraction. The error keeps
|
|
186
|
+
* the caller's spelling of the path; I/O uses the canonical path.
|
|
187
|
+
*/
|
|
188
|
+
const requireExtractableFormat = async (path, input) => {
|
|
189
|
+
const format = input.inputFormat;
|
|
190
|
+
const directory = (await lstat(path)).isDirectory();
|
|
191
|
+
if (!directory &&
|
|
192
|
+
format !== "asar" &&
|
|
193
|
+
format !== "mach-o" &&
|
|
194
|
+
!isZipFormat(format))
|
|
195
|
+
throw new AnalysisUnsupportedTargetError("extract_artifact", input.inputPath, `Artifact format has no extraction reader: ${format}`);
|
|
196
|
+
return directory;
|
|
197
|
+
};
|
|
198
|
+
const createReader = async (path, input) => {
|
|
199
|
+
const format = input.inputFormat;
|
|
200
|
+
if (await requireExtractableFormat(path, input))
|
|
138
201
|
return new DirectoryArtifactReader(path);
|
|
139
202
|
if (format === "asar")
|
|
140
203
|
return new AsarArtifactReader(path);
|
|
141
|
-
if (format
|
|
142
|
-
format === "apk" ||
|
|
143
|
-
format === "msix" ||
|
|
144
|
-
format === "appx" ||
|
|
145
|
-
format === "zip")
|
|
204
|
+
if (isZipFormat(format))
|
|
146
205
|
return new ZipArtifactReader(path, format);
|
|
147
|
-
|
|
148
|
-
return new MachOSliceArtifactReader(path);
|
|
149
|
-
throw new ArtifactReaderFailure("unavailable", `Artifact format has no extraction reader: ${format}`);
|
|
206
|
+
return new MachOSliceArtifactReader(path, input.environment);
|
|
150
207
|
};
|
|
151
208
|
const preflight = (entry) => {
|
|
152
209
|
if ((entry.kind !== "file" && entry.kind !== "slice") || entry.encrypted)
|