rea-agents 6.3.0 → 6.4.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 -4
- package/bridge/ghidra/ReaGhidraApplySeeds.java +151 -0
- package/bridge/ghidra/ReaGhidraBridge.java +597 -209
- package/bridge/ghidra/ReaGhidraNoReturnFix.java +123 -0
- package/dist/adb/AdbConfiguration.js +88 -0
- package/dist/adb/AdbDeviceOutput.js +186 -0
- package/dist/adb/AdbProvider.js +1190 -0
- package/dist/adb/AdbShellOutput.js +309 -0
- package/dist/android/AndroidTargetSnapshot.js +104 -22
- package/dist/android/JadxConfiguration.js +44 -24
- package/dist/android/JadxProvider.js +51 -19
- package/dist/apktool/ApktoolConfiguration.js +84 -0
- package/dist/apktool/ApktoolDecodeOutput.js +59 -0
- package/dist/apktool/ApktoolProvider.js +506 -0
- package/dist/application/AnalysisProvider.js +8 -2
- package/dist/application/AppBundleExecutable.js +27 -22
- package/dist/application/BinaryTargetResolver.js +22 -2
- package/dist/application/CapabilityInventory.js +11 -1
- package/dist/application/ClientConfigurationDocument.js +70 -0
- package/dist/application/ClientConfigurationFiles.js +91 -0
- package/dist/application/ClientRegistrationEnvironment.js +35 -0
- package/dist/application/ClientRegistrationStatus.js +66 -31
- package/dist/application/DirectAnalysis.js +2 -2
- package/dist/application/DirectAnalysisCleanup.js +1 -1
- package/dist/application/DirectAnalysisStatus.js +1 -1
- package/dist/application/Doctor.js +5 -3
- package/dist/application/DoctorDiagnostics.js +1 -1
- package/dist/application/EvidenceBundleCommands.js +6 -12
- package/dist/application/GeminiClientSettings.js +139 -0
- package/dist/application/HermesClientHome.js +115 -0
- package/dist/application/HopperDownload.js +39 -0
- package/dist/application/InvestigationProviders.js +6 -0
- package/dist/application/JsonFiles.js +6 -5
- package/dist/{cliJsonFile.js → application/JsonInputFile.js} +108 -35
- package/dist/application/LinuxHopper.js +4 -12
- package/dist/application/MacHopper.js +172 -149
- package/dist/application/MipsElfAbiFlags.js +140 -0
- package/dist/application/ProviderOperationExecution.js +31 -0
- package/dist/application/ReconstructionObligationCandidates.js +9 -3
- package/dist/application/ReferenceSourceImport.js +76 -29
- package/dist/application/ReferenceSourceImportEntries.js +18 -9
- package/dist/application/ReferenceSourceImportPolicy.js +99 -23
- package/dist/application/ReferenceSourceImportTypes.js +30 -22
- package/dist/application/ReferenceSourceVcsAdapter.js +145 -30
- package/dist/application/RegularFileRead.js +93 -7
- package/dist/application/Setup.js +54 -6
- package/dist/application/SetupClientConfiguration.js +116 -16
- package/dist/application/SetupHost.js +102 -24
- package/dist/application/SetupPlan.js +5 -8
- package/dist/application/SetupSkill.js +58 -39
- package/dist/application/SupportedClients.js +290 -65
- package/dist/application/Uninstall.js +158 -10
- package/dist/application/UpdateMaintenance.js +17 -21
- package/dist/application/Utf8JsonInput.js +7 -0
- package/dist/application/WebScriptExportService.js +131 -65
- package/dist/application/WebSourceLocationService.js +3 -0
- package/dist/application/adb/AdbDeviceAnalysisPort.js +1 -0
- package/dist/application/adb/AdbDeviceAnalysisService.js +13 -0
- package/dist/application/analysisView/AnalysisViewService.js +40 -2
- package/dist/application/apktool/ApktoolResourceAnalysisPort.js +1 -0
- package/dist/application/apktool/ApktoolResourceAnalysisService.js +13 -0
- package/dist/application/binary/AnalysisClientCleanup.js +0 -24
- package/dist/application/binary/BinarySession.js +2 -1
- package/dist/application/binaryDiagnostics/BinaryLayoutService.js +2 -1
- package/dist/application/binaryDiagnostics/PeResourcesPort.js +1 -0
- package/dist/application/binaryDiagnostics/PeResourcesService.js +111 -0
- package/dist/application/binaryDiagnostics/RecordedCrashService.js +2 -1
- package/dist/application/evm/EvmInterfaceService.js +3 -0
- package/dist/application/firmware/FirmwareAnalysisService.js +3 -0
- package/dist/application/investigation/InspectEvidenceBundle.js +18 -0
- package/dist/application/javascript/ElectronBoundaryGraphContext.js +3 -2
- package/dist/application/javascript/ElectronBoundaryGraphIpc.js +2 -2
- package/dist/application/javascript/ElectronBoundaryGraphNative.js +19 -6
- package/dist/application/javascript/ElectronBoundaryGraphWindows.js +3 -3
- package/dist/application/javascript/JavaScriptApplicationService.js +22 -11
- package/dist/application/javascript/JavaScriptApplicationWorkflowEvidence.js +5 -6
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +171 -30
- package/dist/application/javascript/JavaScriptArtifactGraphAccumulator.js +14 -16
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +67 -19
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +4 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +11 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +19 -16
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +92 -10
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +258 -235
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +115 -26
- package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +4 -1
- package/dist/application/javascript/JavaScriptModuleRelationships.js +6 -4
- package/dist/application/javascript/JavaScriptRecoveryService.js +3 -0
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +9 -3
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +199 -61
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +12 -19
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +4 -1
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +5 -3
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +5 -3
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +19 -8
- package/dist/application/jeb/JebAnalysisPort.js +1 -0
- package/dist/application/jeb/JebAnalysisService.js +13 -0
- package/dist/application/managed/ManagedApplicationGraphService.js +1 -1
- package/dist/application/native/NativeUiActionTrace.js +16 -8
- package/dist/application/native/NativeValueTrace.js +23 -6
- package/dist/application/process/ProcessCli.js +25 -20
- package/dist/artifacts/ArtifactPaths.js +129 -8
- package/dist/artifacts/ArtifactProvider.js +20 -15
- package/dist/artifacts/ArtifactReader.js +23 -0
- package/dist/artifacts/ArtifactResourceScope.js +100 -0
- package/dist/artifacts/AsarArtifactReader.js +176 -102
- package/dist/artifacts/AsarHeader.js +24 -0
- package/dist/artifacts/DirectoryArtifactReader.js +168 -65
- package/dist/artifacts/MachOSliceArtifactReader.js +116 -39
- package/dist/artifacts/NativeDmgArtifactReader.js +29 -22
- package/dist/artifacts/SafeOutputTree.js +245 -70
- package/dist/artifacts/SafeOutputTreeCleanup.js +45 -0
- package/dist/artifacts/SafeOutputTreeCreationFailure.js +20 -0
- package/dist/artifacts/SafeOutputTreeIdentity.js +42 -0
- package/dist/artifacts/SafeOutputTreeReadback.js +33 -0
- package/dist/artifacts/ZipArtifactReader.js +77 -27
- package/dist/artifacts/apple/InterfaceBuilderAnalysis.js +58 -18
- package/dist/artifacts/apple/InterfaceBuilderDecodeBudget.js +62 -24
- package/dist/artifacts/apple/KeyedArchiveReader.js +32 -13
- package/dist/artifacts/extraction/ArtifactExtraction.js +110 -86
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +110 -43
- package/dist/artifacts/inventory/ArtifactInventory.js +5 -4
- package/dist/artifacts/inventory/classify.js +75 -32
- package/dist/artifacts/inventory/hashStableRootArtifact.js +48 -15
- package/dist/artifacts/inventory/reader.js +13 -5
- package/dist/artifacts/inventory/scanCanonical.js +62 -25
- package/dist/artifacts/inventory/scanReader.js +38 -11
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +15 -9
- package/dist/artifacts/javascript/JavaScriptSourceAnalysis.js +3 -0
- package/dist/browser/BrowserScenarioPartialObservation.js +8 -2
- package/dist/browser/BrowserScenarioSecrets.js +52 -37
- package/dist/browser/CdpBrowserProvider.js +5 -0
- package/dist/browser/CdpCaptureDocuments.js +40 -6
- package/dist/browser/CdpCaptureDomSvg.js +210 -0
- package/dist/browser/CdpCaptureEventBodyShapes.js +4 -8
- package/dist/browser/CdpCaptureEventHandlers.js +26 -9
- package/dist/browser/CdpCaptureEvents.js +4 -9
- package/dist/browser/CdpConnection.js +22 -5
- package/dist/browser/CdpPageCapture.js +1 -1
- package/dist/browser/CdpTargetSession.js +30 -34
- package/dist/browser/CdpWebMcpDiscovery.js +32 -10
- package/dist/browser/ElectronFileScope.js +99 -9
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +60 -4
- package/dist/browser/PlaywrightElectronActiveProvider.js +11 -6
- package/dist/browser/PlaywrightScenarioArtifacts.js +5 -5
- package/dist/browser/PlaywrightScenarioBrowser.js +69 -7
- package/dist/browser/PlaywrightScenarioSession.js +127 -54
- package/dist/browser/PlaywrightScenarioStorage.js +507 -0
- package/dist/browser/PngVisualDiff.js +198 -29
- package/dist/browser/WebSourceMapFetcher.js +3 -3
- package/dist/browser/assets/LocalWebScriptArtifacts.js +3 -1
- package/dist/browser/assets/PublishWebScripts.js +75 -20
- package/dist/browser/assets/WebArtifactReads.js +23 -1
- package/dist/browser/assets/WebSourceLocationArtifacts.js +1 -0
- package/dist/browser/execution/CdpExecutionCapture.js +3 -3
- package/dist/browser/execution/CdpPreciseCoverage.js +5 -8
- package/dist/browser/history/HarCapture.js +14 -0
- package/dist/browser/history/HarCaptureProcess.js +2 -10
- package/dist/browser/history/MitmproxyCaptureAdapter.js +3 -1
- package/dist/browser/modules/WebModuleArtifacts.js +1 -0
- package/dist/cli/adbCommands.js +337 -0
- package/dist/cli/analysisViewCommands.js +39 -1
- package/dist/cli/apktoolCommands.js +53 -0
- package/dist/cli/artifactCommands.js +8 -11
- package/dist/cli/binaryDiagnosticsCommands.js +19 -1
- package/dist/cli/browserAdvancedCommands.js +65 -36
- package/dist/cli/coreBinaryCommands.js +0 -5
- package/dist/cli/coreNativeCommands.js +1 -14
- package/dist/cli/electronCommands.js +6 -1
- package/dist/cli/evmCommands.js +13 -4
- package/dist/cli/firmwareCommands.js +7 -2
- package/dist/cli/javascriptApplicationAnalysis.js +17 -1
- package/dist/cli/javascriptRecoveryCommands.js +22 -15
- package/dist/cli/jebCommands.js +99 -0
- package/dist/cli/jsonOutput.js +11 -4
- package/dist/cli/referenceSourceImportStatus.js +7 -0
- package/dist/cli/setupCommands.js +15 -3
- package/dist/cli/utilityCommands.js +66 -18
- package/dist/cli/webScriptCommands.js +20 -1
- package/dist/cli/webSourceLocationCommands.js +21 -9
- package/dist/cli.js +6 -0
- package/dist/cliBrowserScenarioCommands.js +2 -1
- package/dist/cliCommandNames.js +32 -0
- package/dist/cliJsonInput.js +2 -2
- package/dist/cliObservationOptions.js +3 -0
- package/dist/composition/adb.js +3 -0
- package/dist/composition/apktool.js +3 -0
- package/dist/composition/binaryDiagnostics.js +4 -0
- package/dist/composition/directAnalysis.js +12 -4
- package/dist/composition/javascriptAnalysisWorkerProcess.js +48 -0
- package/dist/composition/jeb.js +6 -0
- package/dist/config/environment.js +10 -0
- package/dist/config/ghidraLanguageOverride.js +9 -0
- package/dist/config/mcpInputSchemaProfile.js +27 -0
- package/dist/config/parseConfig.js +28 -1
- package/dist/contracts/adb/adbToolContracts.js +353 -0
- package/dist/contracts/advertisedInputExamples.js +48 -0
- package/dist/contracts/analysisDetail.js +10 -0
- package/dist/contracts/analysisViewToolContracts.js +17 -2
- package/dist/contracts/apktool/apktoolToolContracts.js +33 -0
- package/dist/contracts/artifactToolContracts.js +8 -5
- package/dist/contracts/browserToolContracts.js +1 -1
- package/dist/contracts/compactInputSchema.js +256 -0
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/inputSchemaPresentation.js +10 -10
- package/dist/contracts/javascript/electronToolContracts.js +15 -3
- package/dist/contracts/javascript/javascriptRecoveryToolContracts.js +1 -1
- package/dist/contracts/jeb/jebToolContracts.js +64 -0
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +25 -3
- package/dist/contracts/officialToolContracts.js +5 -5
- package/dist/contracts/sessionToolContracts.js +2 -2
- package/dist/contracts/sessionToolSchemas.js +6 -2
- package/dist/contracts/toolContractExamples.js +6 -0
- package/dist/contracts/toolContractTypes.js +3 -0
- package/dist/contracts/toolContracts.js +6 -0
- package/dist/contracts/toolEffects.js +167 -0
- package/dist/contracts/toolOutputSchemaGroups.js +5 -3
- package/dist/contracts/toolSchemaMetadata.js +82 -7
- package/dist/domain/adb/adbDeviceAnalysis.js +583 -0
- package/dist/domain/analysisErrorCleanup.js +29 -0
- package/dist/domain/analysisErrorPresentation.js +18 -6
- package/dist/domain/analysisErrorProjection.js +4 -1
- package/dist/domain/analysisSnapshot.js +2 -1
- package/dist/domain/analysisView/analysisView.js +52 -2
- package/dist/domain/analysisView/binaryLayoutView.js +2 -0
- package/dist/domain/analysisView/javascriptApplicationView.js +2 -0
- package/dist/domain/analysisView/nativeFunctionView.js +155 -0
- package/dist/domain/android/androidApplication.js +25 -20
- package/dist/domain/apktool/apktoolResourceAnalysis.js +77 -0
- package/dist/domain/apple/appleApplication.js +40 -23
- package/dist/domain/apple/appleBundleAnatomy.js +95 -28
- package/dist/domain/apple/dyldPaths.js +9 -1
- package/dist/domain/apple/dylibResolution.js +2 -2
- package/dist/domain/apple/interfaceBuilderGraph.js +22 -19
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +10 -1
- package/dist/domain/artifactComparison.js +35 -7
- package/dist/domain/artifactGraph.js +5 -3
- package/dist/domain/artifactIdentity.js +30 -2
- package/dist/domain/artifactInspection.js +3 -43
- package/dist/domain/artifactIntegrityPolicy.js +10 -0
- package/dist/domain/artifactInventoryEvidence.js +11 -12
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/binaryTarget.js +16 -0
- package/dist/domain/binaryTargetTypes.js +8 -1
- package/dist/domain/browserObservationSchemas.js +8 -4
- package/dist/domain/canonicalJsonDigestSteps.js +34 -12
- package/dist/domain/compactStringIdentity.js +9 -0
- package/dist/domain/evidence.js +2 -1
- package/dist/domain/evidenceRecordSummary.js +144 -0
- package/dist/domain/inputIssueProjection.js +16 -1
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +12 -13
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +11 -20
- package/dist/domain/javascript/electronStaticAnalysisNative.js +70 -40
- package/dist/domain/javascript/electronStaticAnalysisValues.js +16 -0
- package/dist/domain/javascript/javascriptAnalysisResourceControls.js +45 -0
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +4 -1
- package/dist/domain/javascript/javascriptApplicationChangeGraph.js +6 -6
- package/dist/domain/javascript/javascriptApplicationGraph.js +79 -18
- package/dist/domain/javascript/javascriptApplicationProjectionResources.js +35 -0
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +28 -12
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +9 -1
- package/dist/domain/javascript/javascriptAstFingerprint.js +58 -31
- package/dist/domain/javascript/javascriptAstValues.js +32 -0
- package/dist/domain/javascript/javascriptElectronMemberWrites.js +50 -0
- package/dist/domain/javascript/javascriptModuleSemanticIr.js +15 -0
- package/dist/domain/javascript/javascriptNativeHandoff.js +6 -1
- package/dist/domain/javascript/javascriptRpcEndpoints.js +253 -0
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +1 -3
- package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +7 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +8 -11
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +190 -33
- package/dist/domain/javascript/javascriptSemanticCallableResults.js +42 -0
- package/dist/domain/javascript/javascriptSemanticCalls.js +8 -1
- package/dist/domain/javascript/javascriptSemanticDerivedAnalysis.js +15 -4
- package/dist/domain/javascript/javascriptSemanticFileProjection.js +1 -0
- package/dist/domain/javascript/javascriptSemanticFingerprints.js +42 -41
- package/dist/domain/javascript/javascriptSemanticGraph.js +69 -23
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +2 -10
- package/dist/domain/javascript/javascriptSemanticIterationSources.js +40 -7
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +341 -87
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +78 -35
- package/dist/domain/javascript/javascriptSemanticObjectReferences.js +381 -0
- package/dist/domain/javascript/javascriptSemanticObjects.js +7 -1
- package/dist/domain/javascript/javascriptSemanticProjection.js +52 -14
- package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +77 -0
- package/dist/domain/javascript/javascriptSemanticQuery.js +27 -29
- package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +1 -3
- package/dist/domain/javascript/javascriptSemanticReturnedReferences.js +219 -0
- package/dist/domain/javascript/javascriptSemanticReturns.js +13 -23
- package/dist/domain/javascript/javascriptSemanticState.js +22 -2
- package/dist/domain/javascript/javascriptSemanticTraversal.js +19 -1
- package/dist/domain/javascript/javascriptSemanticValues.js +47 -19
- package/dist/domain/javascript/javascriptSourceAnalysis.js +1 -0
- package/dist/domain/javascript/javascriptStaticAnalysis.js +29 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +8 -6
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +49 -5
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +8 -4
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +1 -0
- package/dist/domain/jeb/jebAnalysis.js +114 -0
- package/dist/domain/jsonShape.js +63 -52
- package/dist/domain/jsonValue.js +3 -0
- package/dist/domain/managed/managedApplicationGraph.js +37 -0
- package/dist/domain/managed/managedApplicationGraphCoverage.js +8 -2
- package/dist/domain/managed/managedApplicationGraphNodes.js +32 -22
- package/dist/domain/managed/managedArtifact.js +1 -0
- package/dist/domain/managed/managedInspectionEvidence.js +13 -0
- package/dist/domain/native/nativeAotPe.js +1408 -0
- package/dist/domain/native/nativeInstruction.js +21 -0
- package/dist/domain/native/nativeMetadataRecovery.js +79 -6
- package/dist/domain/native/peResources.js +94 -0
- package/dist/domain/nativeConvention.js +33 -0
- package/dist/domain/process/processCapture.js +91 -1
- package/dist/domain/process/processCaptureExample.js +24 -0
- package/dist/domain/process/processCaptureValidation.js +79 -0
- package/dist/domain/process/processScenario.js +59 -7
- package/dist/domain/propertyListKeys.js +3 -1
- package/dist/domain/referenceSourceGraph.js +25 -16
- package/dist/domain/referenceSourceImportParsing.js +6 -3
- package/dist/domain/referenceSourcePathIdentity.js +22 -0
- package/dist/domain/referenceSourceRequireBindings.js +137 -0
- package/dist/domain/webBundleAnalyzerInspection.js +14 -2
- package/dist/domain/webCaptureDiff.js +102 -4
- package/dist/domain/webScriptExportError.js +10 -4
- package/dist/domain/webScriptExportPlan.js +7 -13
- package/dist/domain/zipPackageFormat.js +4 -1
- package/dist/domain/zodCollectionSteps.js +24 -0
- package/dist/dotnet/ManagedArtifactInspector.js +55 -43
- package/dist/dotnet/ManagedDecodeBudget.js +80 -0
- package/dist/dotnet/ManagedMemberInspector.js +13 -6
- package/dist/dotnet/ManagedMemberInspectorCore.js +2 -2
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +4 -2
- package/dist/dotnet/ManagedMemberRows.js +9 -4
- package/dist/dotnet/ManagedMetadataHeaps.js +15 -5
- package/dist/dotnet/ManagedMetadataInventoryRows.js +20 -11
- package/dist/dotnet/ManagedMetadataLayout.js +10 -4
- package/dist/dotnet/ManagedMethodBodyReader.js +8 -3
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +3 -2
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +49 -34
- package/dist/dotnet/ManagedPeReader.js +41 -25
- package/dist/dotnet/ManagedReaderFailure.js +2 -1
- package/dist/dotnet/ManagedStaticProvider.js +55 -24
- package/dist/evaluation/AgentEvaluationReport.js +9 -5
- package/dist/evaluation/CodexAgentEval.js +43 -13
- package/dist/evm/EvmoleFailures.js +0 -2
- package/dist/evm/EvmoleInterfaceProvider.js +67 -2
- package/dist/filesystem/OwnedDirectoryHandle.js +29 -0
- package/dist/filesystem/OwnedFileHandle.js +36 -0
- package/dist/filesystem/RegularFile.js +33 -1
- package/dist/filesystem/StableFileHash.js +46 -0
- package/dist/filesystem/readFileHandleChunks.js +26 -0
- package/dist/firmware/FirmwareCommand.js +25 -3
- package/dist/firmware/FirmwareFiles.js +23 -8
- package/dist/firmware/FirmwareProvider.js +156 -32
- package/dist/firmware/FirmwarePublication.js +24 -3
- package/dist/firmware/FirmwareRelease.js +1 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraAnalysisProfile.js +55 -4
- package/dist/ghidra/GhidraAnalysisSeeds.js +211 -0
- package/dist/ghidra/GhidraClient.js +76 -4
- package/dist/ghidra/GhidraDiagnostics.js +11 -8
- package/dist/ghidra/GhidraFunctionValues.js +26 -2
- package/dist/ghidra/GhidraInstallation.js +1 -1
- package/dist/ghidra/GhidraInventoryValues.js +23 -1
- package/dist/ghidra/GhidraLanguageCatalog.js +99 -0
- package/dist/ghidra/GhidraLauncher.js +80 -39
- package/dist/ghidra/GhidraLoadImageAttest.js +49 -2
- package/dist/ghidra/GhidraMipsProfile.js +79 -0
- package/dist/ghidra/GhidraProvider.js +57 -9
- package/dist/ghidra/GhidraProviderCapabilities.js +18 -8
- package/dist/ghidra/GhidraProviderClient.js +282 -21
- package/dist/ghidra/GhidraSessionValues.js +9 -2
- package/dist/hopper/HopperAnalysisProfile.js +2 -0
- package/dist/hopper/HopperClient.js +15 -6
- package/dist/hopper/HopperMachOImage.js +2 -0
- package/dist/hopper/HopperProvider.js +13 -2
- package/dist/ida/IdaOperationRunner.js +8 -2
- package/dist/ida/IdaProvider.js +7 -0
- package/dist/ida/IdaSessionClient.js +3 -1
- package/dist/ida/IdaWorkspace.js +4 -2
- package/dist/javascript/analysis/JavaScriptAnalysisTransfer.js +326 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorker.js +520 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerProtocol.js +63 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerSchemas.js +521 -0
- package/dist/javascript/analysis/JavaScriptAnalysisWorkerServer.js +116 -0
- package/dist/javascript/recovery/RecoveryFiles.js +18 -7
- package/dist/javascript/recovery/WakaruCommand.js +22 -9
- package/dist/javascript/recovery/WakaruExecution.js +11 -7
- package/dist/javascript/recovery/WakaruProvider.js +139 -16
- package/dist/javascript/recovery/WakaruPublication.js +14 -4
- package/dist/javascript/recovery/WakaruRelease.js +10 -3
- package/dist/javascript/recovery/WakaruReport.js +12 -7
- package/dist/javascript/recovery/WakaruVersion.js +24 -0
- package/dist/javascript/sourceMaps/SourceMapCommand.js +16 -3
- package/dist/javascript/sourceMaps/SourceMapDecoder.js +63 -7
- package/dist/javascript/sourceMaps/SourceMapFormat.js +15 -4
- package/dist/jeb/JebMcpConnection.js +179 -0
- package/dist/jeb/JebMcpEndpoint.js +40 -0
- package/dist/jeb/JebProvider.js +299 -0
- package/dist/mcpDoctor.js +15 -6
- package/dist/native/AppleDispatchCoverage.js +25 -12
- package/dist/native/AppleDispatchMetadata.js +14 -7
- package/dist/native/AppleMachoFixups.js +71 -15
- package/dist/native/AppleMachoSelection.js +23 -3
- package/dist/native/NativeMacOSProvider.js +91 -16
- package/dist/native/NativeMachoInspection.js +11 -7
- package/dist/native/NativeUiHelperRuntime.js +6 -1
- package/dist/native/NativeUiObservation.js +4 -3
- package/dist/native/pe/PeResourceLayout.js +120 -0
- package/dist/native/pe/PeResourceParser.js +286 -0
- package/dist/native/pe/PeResourcesProvider.js +63 -0
- package/dist/process/BoundedFileBytes.js +30 -7
- package/dist/process/DarwinProcessRunTokenReader.js +8 -3
- package/dist/process/OwnedCommand.js +4 -3
- package/dist/process/ProcessOwnership.js +104 -112
- package/dist/process/ProcessOwnershipObservation.js +96 -39
- package/dist/process/ProcessOwnershipProcessTree.js +4 -4
- package/dist/process/ProcessRunTokenObservations.js +48 -0
- package/dist/process/ProviderDiagnosticRedaction.js +17 -0
- package/dist/process/ProviderProcess.js +4 -3
- package/dist/process/capture/FilesystemSnapshot.js +28 -4
- package/dist/process/capture/ProcessCaptureLifecycle.js +350 -59
- package/dist/process/capture/ProcessCaptureProgress.js +62 -0
- package/dist/process/capture/ProcessHarness.js +194 -26
- package/dist/process/capture/ProcessNormalization.js +3 -1
- package/dist/process/capture/ProcessScenarioRuntimeValidation.js +5 -2
- package/dist/process/capture/TerminalRenderer.js +24 -7
- package/dist/reference/ReferenceSourceReader.js +22 -5
- package/dist/reference/ReferenceSourceReaderEntries.js +114 -51
- package/dist/reference/ReferenceSourceReaderErrors.js +12 -0
- package/dist/reference/ReferenceSourceReaderFile.js +50 -10
- package/dist/reference/ReferenceSourceReaderValidate.js +4 -4
- package/dist/server/EvidenceMcpServer.js +36 -1
- package/dist/server/admittedToolOperation.js +9 -0
- package/dist/server/contractToolHandler.js +21 -0
- package/dist/server/createServer.js +97 -25
- package/dist/server/registerAdbTools.js +36 -0
- package/dist/server/registerAnalysisViewTool.js +4 -9
- package/dist/server/registerAndroidTools.js +3 -12
- package/dist/server/registerApktoolTools.js +14 -0
- package/dist/server/registerApplicationTools/compareExportShapes.js +4 -6
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +4 -5
- package/dist/server/registerApplicationTools/compareVersions.js +3 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -2
- package/dist/server/registerApplicationTools/obligationLedger.js +3 -2
- package/dist/server/registerApplicationTools/projectMobileApplicationGraph.js +3 -2
- package/dist/server/registerApplicationTools/traceFeature.js +3 -2
- package/dist/server/registerApplicationTools/traceSemantics.js +4 -5
- package/dist/server/registerArtifactComparisonTool.js +5 -2
- package/dist/server/registerBinaryDiagnosticsTools.js +16 -4
- package/dist/server/registerBrowserScenarioTool.js +10 -7
- package/dist/server/registerBrowserTools.js +12 -9
- package/dist/server/registerBundleComparisonTool.js +16 -2
- package/dist/server/registerCloseLifecycleTool.js +32 -3
- package/dist/server/registerElectronTools.js +28 -10
- package/dist/server/registerEvmTools.js +4 -9
- package/dist/server/registerFirmwareTools.js +3 -11
- package/dist/server/registerFunctionComparisonTool.js +5 -2
- package/dist/server/registerJavaScriptRecoveryTool.js +4 -9
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +9 -6
- package/dist/server/registerJebTools.js +16 -0
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -6
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -2
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +3 -2
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +3 -2
- package/dist/server/registerPeResourcesTool.js +9 -0
- package/dist/server/registerProcessComparisonTool.js +5 -2
- package/dist/server/registerRecordedCrashTools.js +4 -9
- package/dist/server/registerSessionRecordTools.js +2 -1
- package/dist/server/registerSessionTools.js +49 -18
- package/dist/server/registerWebModuleTool.js +4 -9
- package/dist/server/registerWebNetworkCaptureTool.js +4 -9
- package/dist/server/registerWebRuntimeTools.js +6 -5
- package/dist/server/registerWebScriptTool.js +6 -3
- package/dist/server/registerWebSourceLocationTool.js +4 -9
- package/dist/server/toolResult.js +21 -2
- package/dist/windows/WindowsPrivateRuntime.js +12 -5
- package/install.sh +7 -4
- package/licenses/nativeaot-parser-MIT.txt +28 -0
- package/native/windows/build/manifest.json +2 -2
- package/native/windows/build/rea-windows-x64.node +0 -0
- package/package.json +33 -5
- package/scripts/rea.mjs +16 -1
- package/skills/reverse-engineer-anything/SKILL.md +52 -51
- package/skills/reverse-engineer-anything/references/connection-and-recovery.md +127 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +8 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +92 -13
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +22 -1
|
@@ -3,6 +3,7 @@ import { promisify } from "node:util";
|
|
|
3
3
|
import { errorMessage, systemProcessOwnershipHost as systemHost, } from "./ProcessOwnershipObservation.js";
|
|
4
4
|
import { launcherIdentityFailure } from "./ProcessOwnershipIdentity.js";
|
|
5
5
|
import { descendantsOf, liveProcesses } from "./ProcessOwnershipProcessTree.js";
|
|
6
|
+
import { readProcessRunTokens } from "./ProcessRunTokenObservations.js";
|
|
6
7
|
const execFileAsync = promisify(execFile);
|
|
7
8
|
/**
|
|
8
9
|
* Terminate one Windows process tree through the platform utility.
|
|
@@ -115,7 +116,38 @@ const readLiveProcessTable = async (host) => {
|
|
|
115
116
|
return { available: false, reason: errorMessage(cause) };
|
|
116
117
|
}
|
|
117
118
|
};
|
|
118
|
-
|
|
119
|
+
// A process-table read can race exit and retain the old state with an altered
|
|
120
|
+
// command. Only a fresh table proving that PID is no longer live can settle
|
|
121
|
+
// that mismatch; surviving group members still require normal token checks.
|
|
122
|
+
const settleLauncherExit = async (ownership, processes, host) => {
|
|
123
|
+
const launcher = processes.find(({ pid }) => pid === ownership.leaderPid);
|
|
124
|
+
if (launcher === undefined)
|
|
125
|
+
return processes;
|
|
126
|
+
const reason = launcherIdentityFailure(launcher, ownership);
|
|
127
|
+
if (reason === null)
|
|
128
|
+
return processes;
|
|
129
|
+
const refreshed = await readLiveProcessTable(host);
|
|
130
|
+
if (refreshed.available &&
|
|
131
|
+
!refreshed.processes.some(({ pid }) => pid === launcher.pid)) {
|
|
132
|
+
// Refreshing must not discard a surviving detached descendant's lineage,
|
|
133
|
+
// including a child that changed groups while the launcher exited.
|
|
134
|
+
const descendants = descendantsOf([launcher.pid], processes);
|
|
135
|
+
const descendantPids = new Set(descendants.map(({ pid }) => pid));
|
|
136
|
+
const descendantGroupIds = new Set(descendants.map(({ processGroupId }) => processGroupId));
|
|
137
|
+
const refreshedDescendantPids = new Set(descendantsOf(descendants.map(({ pid }) => pid), refreshed.processes).map(({ pid }) => pid));
|
|
138
|
+
if (refreshed.processes.some((process) => process.processGroupId !== ownership.processGroupId &&
|
|
139
|
+
(refreshedDescendantPids.has(process.pid) ||
|
|
140
|
+
descendantPids.has(process.pid) ||
|
|
141
|
+
descendantGroupIds.has(process.processGroupId))))
|
|
142
|
+
return { cleaned: false, reason };
|
|
143
|
+
return refreshed.processes;
|
|
144
|
+
}
|
|
145
|
+
return { cleaned: false, reason };
|
|
146
|
+
};
|
|
147
|
+
const createOwnedCleanupPlan = async (ownership, initialProcesses, host) => {
|
|
148
|
+
const processes = await settleLauncherExit(ownership, initialProcesses, host);
|
|
149
|
+
if ("cleaned" in processes)
|
|
150
|
+
return processes;
|
|
119
151
|
const sampledProcessGroupIds = new Set((ownership.sampledProcessGroupIds ?? []).filter((processGroupId) => Number.isSafeInteger(processGroupId) && processGroupId > 0));
|
|
120
152
|
const tokenOwned = ownership.sweepTokenOwnedProcesses === true
|
|
121
153
|
? await scanTokenOwnedProcesses(processes, ownership.runId, host, ownership.captureBaseline, {
|
|
@@ -149,10 +181,7 @@ const createOwnedCleanupPlan = async (ownership, processes, host) => {
|
|
|
149
181
|
};
|
|
150
182
|
let descendants = [];
|
|
151
183
|
if (launcher !== undefined) {
|
|
152
|
-
|
|
153
|
-
if (identityFailure !== null)
|
|
154
|
-
return { cleaned: false, reason: identityFailure };
|
|
155
|
-
descendants = descendantsOf(launcher.pid, processes);
|
|
184
|
+
descendants = descendantsOf([launcher.pid], processes);
|
|
156
185
|
}
|
|
157
186
|
const descendantPids = new Set(descendants.map(({ pid }) => pid));
|
|
158
187
|
const processGroupIds = new Set([ownership.processGroupId]);
|
|
@@ -218,7 +247,10 @@ const createOwnedCleanupPlan = async (ownership, processes, host) => {
|
|
|
218
247
|
const revalidateOwnedProcessGroup = async (processGroupId, ownership, host, expectedIdentities) => {
|
|
219
248
|
let members;
|
|
220
249
|
try {
|
|
221
|
-
|
|
250
|
+
const processes = await settleLauncherExit(ownership, liveProcesses(await host.listProcesses()), host);
|
|
251
|
+
if ("cleaned" in processes)
|
|
252
|
+
return processes;
|
|
253
|
+
members = processes.filter(({ processGroupId: observedGroupId }) => observedGroupId === processGroupId);
|
|
222
254
|
}
|
|
223
255
|
catch (cause) {
|
|
224
256
|
return {
|
|
@@ -229,14 +261,6 @@ const revalidateOwnedProcessGroup = async (processGroupId, ownership, host, expe
|
|
|
229
261
|
const failures = await processOwnershipFailures(members, ownership.runId, host, expectedIdentities);
|
|
230
262
|
if (failures.length > 0)
|
|
231
263
|
return cleanupValidationFailure(failures);
|
|
232
|
-
if (processGroupId === ownership.processGroupId) {
|
|
233
|
-
const launcher = members.find(({ pid }) => pid === ownership.leaderPid);
|
|
234
|
-
if (launcher !== undefined) {
|
|
235
|
-
const identityFailure = launcherIdentityFailure(launcher, ownership);
|
|
236
|
-
if (identityFailure !== null)
|
|
237
|
-
return { cleaned: false, reason: identityFailure };
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
264
|
if (processGroupId !== ownership.processGroupId &&
|
|
241
265
|
members.length > 0 &&
|
|
242
266
|
!members.some(({ pid }) => pid === processGroupId) &&
|
|
@@ -328,53 +352,29 @@ const processOwnershipFailures = async (members, runId, host, expectedIdentities
|
|
|
328
352
|
if (expectedIdentities.size > 0 && host.processIdentities !== undefined) {
|
|
329
353
|
const expectedMembers = members.filter(({ pid }) => expectedIdentities.has(pid));
|
|
330
354
|
const observed = await host.processIdentities(expectedMembers);
|
|
355
|
+
const identityFailures = [];
|
|
331
356
|
for (const member of expectedMembers) {
|
|
332
357
|
const expected = expectedIdentities.get(member.pid);
|
|
333
358
|
const current = observed.get(member.pid);
|
|
334
359
|
if (expected === null ||
|
|
335
360
|
current?.state !== "readable" ||
|
|
336
361
|
current.identity !== expected) {
|
|
337
|
-
|
|
338
|
-
continue;
|
|
339
|
-
failures.push({
|
|
362
|
+
identityFailures.push({
|
|
340
363
|
pid: member.pid,
|
|
341
364
|
reason: "process-identity-unavailable",
|
|
342
365
|
diagnostic: "process identity changed or became unavailable before signal",
|
|
343
366
|
});
|
|
344
367
|
}
|
|
345
368
|
}
|
|
369
|
+
failures.push(...(await recheckOwnershipFailures(identityFailures, host)));
|
|
346
370
|
}
|
|
347
|
-
|
|
348
|
-
try {
|
|
349
|
-
if ((await host.environment(member.pid)).REA_PROCESS_RUN_ID !== runId)
|
|
350
|
-
failures.push({ pid: member.pid, reason: "run-token-mismatch" });
|
|
351
|
-
}
|
|
352
|
-
catch (cause) {
|
|
353
|
-
try {
|
|
354
|
-
const live = liveProcesses(await host.listProcesses());
|
|
355
|
-
if (!live.some(({ pid }) => pid === member.pid))
|
|
356
|
-
continue;
|
|
357
|
-
}
|
|
358
|
-
catch (recheckCause) {
|
|
359
|
-
failures.push({
|
|
360
|
-
pid: member.pid,
|
|
361
|
-
reason: "environment-unreadable",
|
|
362
|
-
diagnostic: `${errorMessage(cause)}; process liveness recheck failed: ${errorMessage(recheckCause)}`,
|
|
363
|
-
});
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
failures.push({
|
|
367
|
-
pid: member.pid,
|
|
368
|
-
reason: "environment-unreadable",
|
|
369
|
-
diagnostic: errorMessage(cause),
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
}
|
|
371
|
+
failures.push(...(await processRunTokenFailures(members, runId, host)));
|
|
373
372
|
if (failures.length === 0 &&
|
|
374
373
|
expectedIdentities.size > 0 &&
|
|
375
374
|
host.processIdentities !== undefined) {
|
|
376
375
|
const expectedMembers = members.filter(({ pid }) => expectedIdentities.has(pid));
|
|
377
376
|
const observed = await host.processIdentities(expectedMembers);
|
|
377
|
+
const identityFailures = [];
|
|
378
378
|
for (const member of expectedMembers) {
|
|
379
379
|
const expected = expectedIdentities.get(member.pid);
|
|
380
380
|
const current = observed.get(member.pid);
|
|
@@ -382,17 +382,53 @@ const processOwnershipFailures = async (members, runId, host, expectedIdentities
|
|
|
382
382
|
current?.state === "readable" &&
|
|
383
383
|
current.identity === expected)
|
|
384
384
|
continue;
|
|
385
|
-
|
|
386
|
-
continue;
|
|
387
|
-
failures.push({
|
|
385
|
+
identityFailures.push({
|
|
388
386
|
pid: member.pid,
|
|
389
387
|
reason: "process-identity-unavailable",
|
|
390
388
|
diagnostic: "process identity changed or became unavailable during token validation",
|
|
391
389
|
});
|
|
392
390
|
}
|
|
391
|
+
failures.push(...(await recheckOwnershipFailures(identityFailures, host)));
|
|
393
392
|
}
|
|
394
393
|
return failures;
|
|
395
394
|
};
|
|
395
|
+
const processRunTokenFailures = async (members, runId, host) => {
|
|
396
|
+
const failures = [];
|
|
397
|
+
for await (const { process: member, observation } of readProcessRunTokens(host, members)) {
|
|
398
|
+
if (observation.state === "readable") {
|
|
399
|
+
if (observation.runId !== runId)
|
|
400
|
+
failures.push({ pid: member.pid, reason: "run-token-mismatch" });
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
failures.push({
|
|
404
|
+
pid: member.pid,
|
|
405
|
+
reason: "environment-unreadable",
|
|
406
|
+
diagnostic: observation.reason,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return recheckOwnershipFailures(failures, host);
|
|
410
|
+
};
|
|
411
|
+
/**
|
|
412
|
+
* Take a fresh liveness snapshot after each ownership-read phase. Only an
|
|
413
|
+
* absent PID resolves an unreadable observation; a readable token mismatch
|
|
414
|
+
* remains a failure. Never reuse this snapshot across identity/token reads.
|
|
415
|
+
*/
|
|
416
|
+
const recheckOwnershipFailures = async (failures, host) => {
|
|
417
|
+
if (!failures.some(({ reason }) => reason !== "run-token-mismatch"))
|
|
418
|
+
return failures;
|
|
419
|
+
try {
|
|
420
|
+
const live = new Set(liveProcesses(await host.listProcesses()).map(({ pid }) => pid));
|
|
421
|
+
return failures.filter(({ pid, reason }) => reason === "run-token-mismatch" || live.has(pid));
|
|
422
|
+
}
|
|
423
|
+
catch (cause) {
|
|
424
|
+
return failures.map((failure) => failure.reason === "run-token-mismatch"
|
|
425
|
+
? failure
|
|
426
|
+
: {
|
|
427
|
+
...failure,
|
|
428
|
+
diagnostic: `${failure.diagnostic}; process liveness recheck failed: ${errorMessage(cause)}`,
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
};
|
|
396
432
|
const TOKEN_READ_RETRY_ATTEMPTS = 3;
|
|
397
433
|
const TOKEN_READ_RETRY_DELAY_MS = 40;
|
|
398
434
|
/** Darwin reports this when the kernel withholds a platform binary's environment. */
|
|
@@ -433,18 +469,19 @@ const scanTokenOwnedProcesses = async (processes, runId, host, captureBaseline,
|
|
|
433
469
|
const failures = [];
|
|
434
470
|
if (captureBaseline !== undefined && host.processIdentities !== undefined) {
|
|
435
471
|
const stableCandidates = [];
|
|
472
|
+
const identityFailures = [];
|
|
436
473
|
for (const process of candidates) {
|
|
437
474
|
if (candidateIdentities.get(process.pid)?.state === "readable") {
|
|
438
475
|
stableCandidates.push(process);
|
|
439
476
|
continue;
|
|
440
477
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
});
|
|
478
|
+
identityFailures.push({
|
|
479
|
+
pid: process.pid,
|
|
480
|
+
reason: "process-identity-unavailable",
|
|
481
|
+
diagnostic: "process identity was unavailable during token scan",
|
|
482
|
+
});
|
|
447
483
|
}
|
|
484
|
+
failures.push(...(await recheckOwnershipFailures(identityFailures, host)));
|
|
448
485
|
candidates = stableCandidates;
|
|
449
486
|
}
|
|
450
487
|
const owned = [];
|
|
@@ -454,35 +491,21 @@ const scanTokenOwnedProcesses = async (processes, runId, host, captureBaseline,
|
|
|
454
491
|
const identity = candidateIdentities.get(process.pid);
|
|
455
492
|
ownedIdentities.set(process.pid, identity?.state === "readable" ? identity.identity : null);
|
|
456
493
|
};
|
|
457
|
-
let bulkTokens;
|
|
458
|
-
if (host.runTokens !== undefined)
|
|
459
|
-
bulkTokens = await host.runTokens(candidates);
|
|
460
494
|
const unreadable = [];
|
|
461
|
-
for (const process of candidates) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
if (bulkToken.state === "readable") {
|
|
465
|
-
if (bulkToken.runId === runId)
|
|
466
|
-
recordOwned(process);
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
unreadable.push({ process, diagnostic: bulkToken.reason });
|
|
470
|
-
continue;
|
|
471
|
-
}
|
|
472
|
-
try {
|
|
473
|
-
if ((await host.environment(process.pid)).REA_PROCESS_RUN_ID === runId)
|
|
495
|
+
for await (const { process, observation } of readProcessRunTokens(host, candidates)) {
|
|
496
|
+
if (observation.state === "readable") {
|
|
497
|
+
if (observation.runId === runId)
|
|
474
498
|
recordOwned(process);
|
|
475
499
|
}
|
|
476
|
-
|
|
477
|
-
unreadable.push({ process, diagnostic:
|
|
478
|
-
}
|
|
500
|
+
else
|
|
501
|
+
unreadable.push({ process, diagnostic: observation.reason });
|
|
479
502
|
}
|
|
480
503
|
const remaining = await settleUnreadableTokenCandidates(unreadable, runId, host, recordOwned);
|
|
481
504
|
const relatedPids = new Set();
|
|
482
505
|
const relatedGroupIds = new Set();
|
|
483
506
|
if (relation !== undefined) {
|
|
484
507
|
relatedPids.add(relation.leaderPid);
|
|
485
|
-
for (const descendant of descendantsOf(relation.leaderPid, processes))
|
|
508
|
+
for (const descendant of descendantsOf([relation.leaderPid], processes))
|
|
486
509
|
relatedPids.add(descendant.pid);
|
|
487
510
|
relatedGroupIds.add(relation.processGroupId);
|
|
488
511
|
for (const processGroupId of relation.sampledProcessGroupIds ?? [])
|
|
@@ -533,6 +556,7 @@ const scanTokenOwnedProcesses = async (processes, runId, host, captureBaseline,
|
|
|
533
556
|
if (candidates.length > 0 && host.processIdentities !== undefined) {
|
|
534
557
|
const afterRead = await host.processIdentities(candidates);
|
|
535
558
|
const stillOwned = [];
|
|
559
|
+
const identityFailures = [];
|
|
536
560
|
const ownedPids = new Set(owned.map(({ pid }) => pid));
|
|
537
561
|
for (const process of candidates) {
|
|
538
562
|
const before = candidateIdentities.get(process.pid);
|
|
@@ -544,14 +568,13 @@ const scanTokenOwnedProcesses = async (processes, runId, host, captureBaseline,
|
|
|
544
568
|
stillOwned.push(process);
|
|
545
569
|
continue;
|
|
546
570
|
}
|
|
547
|
-
|
|
548
|
-
continue;
|
|
549
|
-
failures.push({
|
|
571
|
+
identityFailures.push({
|
|
550
572
|
pid: process.pid,
|
|
551
573
|
reason: "process-identity-unavailable",
|
|
552
574
|
diagnostic: "process identity changed or became unavailable during token validation",
|
|
553
575
|
});
|
|
554
576
|
}
|
|
577
|
+
failures.push(...(await recheckOwnershipFailures(identityFailures, host)));
|
|
555
578
|
return {
|
|
556
579
|
owned: stillOwned,
|
|
557
580
|
failures,
|
|
@@ -579,29 +602,18 @@ const settleUnreadableTokenCandidates = async (pending, runId, host, recordOwned
|
|
|
579
602
|
void cause;
|
|
580
603
|
live = undefined;
|
|
581
604
|
}
|
|
582
|
-
let observations;
|
|
583
|
-
if (host.runTokens !== undefined) {
|
|
584
|
-
try {
|
|
585
|
-
observations = await host.runTokens(remaining.map(({ process }) => process));
|
|
586
|
-
}
|
|
587
|
-
catch (cause) {
|
|
588
|
-
void cause;
|
|
589
|
-
observations = undefined;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
605
|
const stillUnreadable = [];
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
const observation = observations?.get(pid) ?? (await readEnvironmentRunToken(host, pid));
|
|
606
|
+
const candidates = remaining
|
|
607
|
+
.map(({ process }) => process)
|
|
608
|
+
.filter(({ pid }) => live === undefined || live.has(pid));
|
|
609
|
+
for await (const { process, observation } of readProcessRunTokens(host, candidates)) {
|
|
598
610
|
if (observation.state === "readable") {
|
|
599
611
|
if (observation.runId === runId)
|
|
600
|
-
recordOwned(
|
|
612
|
+
recordOwned(process);
|
|
601
613
|
continue;
|
|
602
614
|
}
|
|
603
615
|
stillUnreadable.push({
|
|
604
|
-
process
|
|
616
|
+
process,
|
|
605
617
|
diagnostic: observation.reason,
|
|
606
618
|
});
|
|
607
619
|
}
|
|
@@ -609,23 +621,3 @@ const settleUnreadableTokenCandidates = async (pending, runId, host, recordOwned
|
|
|
609
621
|
}
|
|
610
622
|
return remaining;
|
|
611
623
|
};
|
|
612
|
-
const readEnvironmentRunToken = async (host, pid) => {
|
|
613
|
-
try {
|
|
614
|
-
return {
|
|
615
|
-
state: "readable",
|
|
616
|
-
runId: (await host.environment(pid)).REA_PROCESS_RUN_ID,
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
catch (cause) {
|
|
620
|
-
return { state: "unavailable", reason: errorMessage(cause) };
|
|
621
|
-
}
|
|
622
|
-
};
|
|
623
|
-
const processIsGone = async (host, pid) => {
|
|
624
|
-
try {
|
|
625
|
-
return !liveProcesses(await host.listProcesses()).some((process) => process.pid === pid);
|
|
626
|
-
}
|
|
627
|
-
catch (cause) {
|
|
628
|
-
void cause;
|
|
629
|
-
return false;
|
|
630
|
-
}
|
|
631
|
-
};
|
|
@@ -4,46 +4,65 @@ import { launcherIdentityFailure } from "./ProcessOwnershipIdentity.js";
|
|
|
4
4
|
import { descendantsOf, liveProcesses } from "./ProcessOwnershipProcessTree.js";
|
|
5
5
|
import { execFileOutput } from "./ExecFileOutput.js";
|
|
6
6
|
import { createDarwinProcessRunTokenReader } from "./DarwinProcessRunTokenReader.js";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { readProcessRunTokens } from "./ProcessRunTokenObservations.js";
|
|
8
|
+
/** Observe multiple groups from one process snapshot and one token batch. */
|
|
9
|
+
export const observeOwnedProcessGroups = async (runId, processGroupIds, host = systemProcessOwnershipHost, signal) => {
|
|
9
10
|
signal?.throwIfAborted();
|
|
10
|
-
|
|
11
|
+
const groupIds = [...new Set(processGroupIds)];
|
|
12
|
+
if (groupIds.length === 0)
|
|
13
|
+
return new Map();
|
|
14
|
+
let processes;
|
|
11
15
|
try {
|
|
12
|
-
|
|
16
|
+
processes = liveProcesses(await host.listProcesses(signal));
|
|
13
17
|
}
|
|
14
18
|
catch (cause) {
|
|
15
19
|
signal?.throwIfAborted();
|
|
16
|
-
|
|
20
|
+
const failure = {
|
|
17
21
|
state: "unverifiable",
|
|
18
22
|
reason: `process group could not be inspected: ${errorMessage(cause)}`,
|
|
19
23
|
};
|
|
24
|
+
return new Map(groupIds.map((groupId) => [groupId, failure]));
|
|
20
25
|
}
|
|
21
26
|
signal?.throwIfAborted();
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
const membersByGroup = new Map(groupIds.map((groupId) => [groupId, []]));
|
|
28
|
+
for (const process of processes)
|
|
29
|
+
membersByGroup.get(process.processGroupId)?.push(process);
|
|
30
|
+
const observations = new Map(groupIds.map((groupId) => [
|
|
31
|
+
groupId,
|
|
32
|
+
(membersByGroup.get(groupId)?.length ?? 0) > 0
|
|
33
|
+
? { state: "alive" }
|
|
34
|
+
: { state: "empty" },
|
|
35
|
+
]));
|
|
36
|
+
const liveMembers = groupIds.flatMap((groupId) => membersByGroup.get(groupId) ?? []);
|
|
37
|
+
const pendingGroups = new Set(groupIds.filter((groupId) => (membersByGroup.get(groupId)?.length ?? 0) > 0));
|
|
38
|
+
for await (const { process: member, observation } of readProcessRunTokens(host, liveMembers, signal)) {
|
|
39
|
+
if (!pendingGroups.has(member.processGroupId))
|
|
40
|
+
continue;
|
|
41
|
+
if (observation.state === "readable") {
|
|
42
|
+
if (observation.runId !== runId) {
|
|
43
|
+
observations.set(member.processGroupId, {
|
|
32
44
|
state: "unverifiable",
|
|
33
45
|
reason: "process ownership did not match",
|
|
34
|
-
};
|
|
46
|
+
});
|
|
47
|
+
pendingGroups.delete(member.processGroupId);
|
|
48
|
+
}
|
|
35
49
|
}
|
|
36
|
-
|
|
50
|
+
else {
|
|
51
|
+
const gone = await processIsGone(host, member.pid);
|
|
37
52
|
signal?.throwIfAborted();
|
|
38
|
-
if (!
|
|
39
|
-
|
|
53
|
+
if (!gone) {
|
|
54
|
+
observations.set(member.processGroupId, {
|
|
40
55
|
state: "unverifiable",
|
|
41
|
-
reason: `process ownership could not be revalidated for PID ${member.pid}: ${
|
|
42
|
-
};
|
|
56
|
+
reason: `process ownership could not be revalidated for PID ${member.pid}: ${observation.reason}`,
|
|
57
|
+
});
|
|
58
|
+
pendingGroups.delete(member.processGroupId);
|
|
43
59
|
}
|
|
44
60
|
}
|
|
61
|
+
if (pendingGroups.size === 0)
|
|
62
|
+
break;
|
|
45
63
|
}
|
|
46
|
-
|
|
64
|
+
signal?.throwIfAborted();
|
|
65
|
+
return observations;
|
|
47
66
|
};
|
|
48
67
|
/**
|
|
49
68
|
* Record the live launcher and descendant lineage after run-token validation.
|
|
@@ -66,23 +85,22 @@ export const observeOwnedProcessLineage = async (ownership, host = systemProcess
|
|
|
66
85
|
const identityFailure = launcherIdentityFailure(launcher, ownership);
|
|
67
86
|
if (identityFailure !== null)
|
|
68
87
|
return unavailableLineage(ownership, identityFailure);
|
|
69
|
-
const descendants = descendantsOf(launcher.pid, processes);
|
|
88
|
+
const descendants = descendantsOf([launcher.pid], processes);
|
|
70
89
|
const verifiedDescendants = [];
|
|
71
|
-
for (const member of [launcher, ...descendants]) {
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
ownership.runId)
|
|
90
|
+
for await (const { process: member, observation } of readProcessRunTokens(host, [launcher, ...descendants])) {
|
|
91
|
+
if (observation.state === "readable") {
|
|
92
|
+
if (observation.runId !== ownership.runId)
|
|
75
93
|
return unavailableLineage(ownership, "process lineage contains an unowned or PID-reused process");
|
|
76
94
|
if (member.pid !== launcher.pid)
|
|
77
95
|
verifiedDescendants.push(member);
|
|
78
96
|
}
|
|
79
|
-
|
|
97
|
+
else {
|
|
80
98
|
if (await processIsGone(host, member.pid)) {
|
|
81
99
|
if (member.pid === launcher.pid)
|
|
82
100
|
return unavailableLineage(ownership, "owned launcher exited during lineage validation");
|
|
83
101
|
continue;
|
|
84
102
|
}
|
|
85
|
-
return unavailableLineage(ownership, `process ownership could not be revalidated for PID ${member.pid}: ${
|
|
103
|
+
return unavailableLineage(ownership, `process ownership could not be revalidated for PID ${member.pid}: ${observation.reason}`);
|
|
86
104
|
}
|
|
87
105
|
}
|
|
88
106
|
return {
|
|
@@ -251,14 +269,15 @@ export const createSystemProcessOwnershipHost = (platform = process.platform, ho
|
|
|
251
269
|
}
|
|
252
270
|
},
|
|
253
271
|
listProcesses,
|
|
254
|
-
async environment(pid) {
|
|
272
|
+
async environment(pid, signal) {
|
|
273
|
+
signal?.throwIfAborted();
|
|
255
274
|
if (platform === "linux")
|
|
256
|
-
return parseProcessEnvironment(await readFile(`/proc/${pid}/environ`, "utf8"));
|
|
275
|
+
return parseProcessEnvironment(await readFile(`/proc/${pid}/environ`, { encoding: "utf8", signal }));
|
|
257
276
|
if (platform === "darwin") {
|
|
258
|
-
const process = (await listProcesses()).find((entry) => entry.pid === pid);
|
|
277
|
+
const process = (await listProcesses(signal)).find((entry) => entry.pid === pid);
|
|
259
278
|
if (process === undefined)
|
|
260
279
|
throw new Error(`process ${String(pid)} is not live`);
|
|
261
|
-
const observation = (await darwinTokens?.read([process]))?.get(pid);
|
|
280
|
+
const observation = (await darwinTokens?.read([process], signal))?.get(pid);
|
|
262
281
|
if (observation === undefined || observation.state === "unavailable")
|
|
263
282
|
throw new Error(observation?.reason ?? "process run token could not be read");
|
|
264
283
|
return observation.runId === undefined
|
|
@@ -267,6 +286,7 @@ export const createSystemProcessOwnershipHost = (platform = process.platform, ho
|
|
|
267
286
|
}
|
|
268
287
|
const { stdout } = await execFileOutput("ps", ["eww", "-p", String(pid)], {
|
|
269
288
|
env: hostEnvironment,
|
|
289
|
+
...(signal === undefined ? {} : { signal }),
|
|
270
290
|
});
|
|
271
291
|
const observedEnvironment = {};
|
|
272
292
|
for (const match of stdout.matchAll(/(?:^|\s)([A-Za-z_][A-Za-z0-9_]*)=([^\s]*)/gu)) {
|
|
@@ -276,13 +296,16 @@ export const createSystemProcessOwnershipHost = (platform = process.platform, ho
|
|
|
276
296
|
}
|
|
277
297
|
return observedEnvironment;
|
|
278
298
|
},
|
|
279
|
-
async runTokens(processes) {
|
|
299
|
+
async runTokens(processes, signal) {
|
|
300
|
+
signal?.throwIfAborted();
|
|
280
301
|
if (platform !== "darwin" || processes.length === 0)
|
|
281
302
|
return new Map();
|
|
282
303
|
try {
|
|
283
|
-
return (await darwinTokens?.read(processes)) ?? new Map();
|
|
304
|
+
return (await darwinTokens?.read(processes, signal)) ?? new Map();
|
|
284
305
|
}
|
|
285
306
|
catch (cause) {
|
|
307
|
+
if (isExpectedAbort(cause, signal))
|
|
308
|
+
throw cause;
|
|
286
309
|
void cause;
|
|
287
310
|
return new Map(processes.map(({ pid }) => [
|
|
288
311
|
pid,
|
|
@@ -303,17 +326,51 @@ export const createSystemProcessOwnershipHost = (platform = process.platform, ho
|
|
|
303
326
|
};
|
|
304
327
|
};
|
|
305
328
|
export const systemProcessOwnershipHost = createSystemProcessOwnershipHost();
|
|
306
|
-
/**
|
|
307
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Observe a live PID's start identity, optionally binding it to an owned run.
|
|
331
|
+
* Token validation is bracketed by identity reads so PID reuse cannot supply
|
|
332
|
+
* the first identity of a different process for an owned launch.
|
|
333
|
+
*/
|
|
334
|
+
export const observeProcessStartIdentity = async (pid, host = systemProcessOwnershipHost, expectedRunId) => {
|
|
308
335
|
const process = (await host.listProcesses()).find((entry) => entry.pid === pid);
|
|
309
336
|
if (process === undefined || liveProcesses([process]).length === 0)
|
|
310
337
|
return undefined;
|
|
311
338
|
if (host.processIdentities === undefined)
|
|
312
339
|
return { state: "unavailable", reason: "process identity is unsupported" };
|
|
313
|
-
|
|
340
|
+
const identity = (await host.processIdentities([process])).get(pid) ?? {
|
|
314
341
|
state: "unavailable",
|
|
315
342
|
reason: "process identity was not returned",
|
|
316
|
-
}
|
|
343
|
+
};
|
|
344
|
+
if (expectedRunId === undefined || identity.state !== "readable")
|
|
345
|
+
return identity;
|
|
346
|
+
let owned = false;
|
|
347
|
+
for await (const { observation } of readProcessRunTokens(host, [process])) {
|
|
348
|
+
if (observation.state === "unavailable")
|
|
349
|
+
return {
|
|
350
|
+
state: "unavailable",
|
|
351
|
+
reason: `process ownership token could not be read for PID ${String(pid)}: ${observation.reason}`,
|
|
352
|
+
};
|
|
353
|
+
if (observation.runId !== expectedRunId)
|
|
354
|
+
return {
|
|
355
|
+
state: "unavailable",
|
|
356
|
+
reason: `process ownership token did not match the captured run for PID ${String(pid)}`,
|
|
357
|
+
};
|
|
358
|
+
owned = true;
|
|
359
|
+
}
|
|
360
|
+
if (!owned)
|
|
361
|
+
return {
|
|
362
|
+
state: "unavailable",
|
|
363
|
+
reason: `process ownership token was not returned for PID ${String(pid)}`,
|
|
364
|
+
};
|
|
365
|
+
const confirmed = await observeProcessStartIdentity(pid, host);
|
|
366
|
+
if (confirmed === undefined || confirmed.state !== "readable")
|
|
367
|
+
return confirmed;
|
|
368
|
+
return confirmed.identity === identity.identity
|
|
369
|
+
? identity
|
|
370
|
+
: {
|
|
371
|
+
state: "unavailable",
|
|
372
|
+
reason: `process identity changed while validating the captured run token for PID ${String(pid)}`,
|
|
373
|
+
};
|
|
317
374
|
};
|
|
318
375
|
/** Revalidate a launch-time start identity immediately before signaling a PID. */
|
|
319
376
|
export const signalProcessWithStartIdentity = async (pid, expectedIdentity, signal, options = {}) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** Exclude process-table entries that the operating system has already reaped. */
|
|
2
2
|
export const liveProcesses = (members) => members.filter(({ state }) => !state.startsWith("Z"));
|
|
3
|
-
/** Return every live-table descendant of
|
|
4
|
-
export const descendantsOf = (
|
|
3
|
+
/** Return every live-table descendant of the selected roots in breadth-first order. */
|
|
4
|
+
export const descendantsOf = (rootPids, processes) => {
|
|
5
5
|
const childrenByParent = new Map();
|
|
6
6
|
for (const process of processes) {
|
|
7
7
|
const siblings = childrenByParent.get(process.parentPid) ?? [];
|
|
@@ -9,8 +9,8 @@ export const descendantsOf = (launcherPid, processes) => {
|
|
|
9
9
|
childrenByParent.set(process.parentPid, siblings);
|
|
10
10
|
}
|
|
11
11
|
const descendants = [];
|
|
12
|
-
const pending =
|
|
13
|
-
const visited = new Set(
|
|
12
|
+
const pending = rootPids.flatMap((pid) => childrenByParent.get(pid) ?? []);
|
|
13
|
+
const visited = new Set(rootPids);
|
|
14
14
|
for (const process of pending) {
|
|
15
15
|
if (visited.has(process.pid))
|
|
16
16
|
continue;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const errorMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
2
|
+
/** Read only ownership tokens, using per-process fallback for missing batch rows. */
|
|
3
|
+
export async function* readProcessRunTokens(host, processes, signal) {
|
|
4
|
+
signal?.throwIfAborted();
|
|
5
|
+
if (processes.length === 0)
|
|
6
|
+
return;
|
|
7
|
+
let batch;
|
|
8
|
+
let batchFailure;
|
|
9
|
+
if (host.runTokens !== undefined) {
|
|
10
|
+
try {
|
|
11
|
+
batch =
|
|
12
|
+
signal === undefined
|
|
13
|
+
? await host.runTokens(processes)
|
|
14
|
+
: await host.runTokens(processes, signal);
|
|
15
|
+
}
|
|
16
|
+
catch (cause) {
|
|
17
|
+
signal?.throwIfAborted();
|
|
18
|
+
batchFailure = errorMessage(cause);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const process of processes) {
|
|
22
|
+
signal?.throwIfAborted();
|
|
23
|
+
let observation = batch?.get(process.pid);
|
|
24
|
+
if (observation === undefined) {
|
|
25
|
+
try {
|
|
26
|
+
const environment = signal === undefined
|
|
27
|
+
? await host.environment(process.pid)
|
|
28
|
+
: await host.environment(process.pid, signal);
|
|
29
|
+
observation = {
|
|
30
|
+
state: "readable",
|
|
31
|
+
runId: environment.REA_PROCESS_RUN_ID,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch (cause) {
|
|
35
|
+
signal?.throwIfAborted();
|
|
36
|
+
const reason = errorMessage(cause);
|
|
37
|
+
observation = {
|
|
38
|
+
state: "unavailable",
|
|
39
|
+
reason: batchFailure === undefined
|
|
40
|
+
? reason
|
|
41
|
+
: `${reason}; run-token batch failed: ${batchFailure}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
signal?.throwIfAborted();
|
|
46
|
+
yield { process, observation };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Redact explicit transport credentials from complete and budget-cut output. */
|
|
2
|
+
export const redactCapturedTransportCredential = (stream, token, replacement) => {
|
|
3
|
+
if (token === undefined || token.length === 0)
|
|
4
|
+
return stream.text;
|
|
5
|
+
const { text } = stream;
|
|
6
|
+
const cutOff = stream.observedBytes > stream.bytes;
|
|
7
|
+
if (cutOff && !text.endsWith(token)) {
|
|
8
|
+
const maximumPrefixLength = Math.min(text.length, token.length - 1);
|
|
9
|
+
for (let prefixLength = maximumPrefixLength; prefixLength > 0; prefixLength -= 1) {
|
|
10
|
+
if (text.endsWith(token.slice(0, prefixLength)))
|
|
11
|
+
return `${text
|
|
12
|
+
.slice(0, text.length - prefixLength)
|
|
13
|
+
.replaceAll(token, replacement)}${replacement}`;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return text.replaceAll(token, replacement);
|
|
17
|
+
};
|