rea-agents 6.2.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 +24 -23
- package/bridge/ghidra/ReaGhidraApplySeeds.java +151 -0
- package/bridge/ghidra/ReaGhidraBridge.java +597 -209
- package/bridge/ghidra/ReaGhidraNoReturnFix.java +123 -0
- package/bridge/hopper_bridge.py +2 -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 +59 -21
- package/dist/android/JadxSession.js +51 -9
- 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 +85 -19
- package/dist/application/BrowserScenarioEvidence.js +2 -2
- package/dist/application/CapabilityInventory.js +11 -1
- package/dist/application/ClientConfigurationDocument.js +98 -0
- package/dist/application/ClientConfigurationFiles.js +91 -0
- package/dist/application/ClientRegistrationEnvironment.js +35 -0
- package/dist/application/ClientRegistrationStatus.js +75 -27
- package/dist/application/DirectAnalysis.js +14 -8
- package/dist/application/DirectAnalysisCleanup.js +1 -2
- package/dist/application/DirectAnalysisStatus.js +3 -6
- package/dist/application/Doctor.js +27 -34
- package/dist/application/DoctorDiagnostics.js +1 -1
- package/dist/application/EvidenceBundleCommands.js +6 -12
- package/dist/application/EvidenceBundleFiles.js +1 -1
- 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 +10 -4
- package/dist/application/JsonFiles.js +16 -15
- package/dist/application/JsonInputFile.js +252 -0
- package/dist/application/LinuxHopper.js +6 -13
- 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 +16 -3
- package/dist/application/ReconstructionObligationLedgerProjection.js +3 -1
- 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 +103 -0
- package/dist/application/Setup.js +69 -10
- package/dist/application/SetupClientConfiguration.js +134 -23
- package/dist/application/SetupHost.js +102 -22
- package/dist/application/SetupPlan.js +18 -17
- package/dist/application/SetupSkill.js +81 -13
- package/dist/application/SupportedClients.js +305 -37
- package/dist/application/Uninstall.js +172 -8
- package/dist/application/UpdateMaintenance.js +23 -23
- package/dist/application/Utf8JsonInput.js +71 -0
- package/dist/application/WebScriptExportService.js +130 -57
- 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/android/AndroidAnalysisService.js +1 -1
- 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/AnalysisSnapshotCache.js +5 -4
- package/dist/application/binary/BinarySession.js +18 -1
- package/dist/application/binary/BinarySessionOpen.js +9 -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/ElectronActiveEvidence.js +2 -2
- package/dist/application/javascript/ElectronBoundaryAnalysis.js +2 -2
- package/dist/application/javascript/ElectronBoundaryGraphContext.js +3 -2
- package/dist/application/javascript/ElectronBoundaryGraphIpc.js +2 -2
- package/dist/application/javascript/ElectronBoundaryGraphNative.js +20 -3
- package/dist/application/javascript/ElectronBoundaryGraphWindows.js +3 -3
- package/dist/application/javascript/JavaScriptApplicationEvidence.js +1 -0
- package/dist/application/javascript/JavaScriptApplicationEvidenceGraph.js +107 -46
- package/dist/application/javascript/JavaScriptApplicationService.js +23 -11
- package/dist/application/javascript/JavaScriptApplicationWorkflowEvidence.js +5 -6
- package/dist/application/javascript/JavaScriptApplicationWorkflowService.js +59 -45
- package/dist/application/javascript/JavaScriptArtifactAnalysis.js +171 -36
- package/dist/application/javascript/JavaScriptArtifactGraphAccumulator.js +14 -16
- package/dist/application/javascript/JavaScriptArtifactGraphBuilder.js +74 -36
- package/dist/application/javascript/JavaScriptArtifactGraphBundlers.js +4 -3
- package/dist/application/javascript/JavaScriptArtifactGraphContext.js +11 -5
- package/dist/application/javascript/JavaScriptArtifactGraphFindings.js +53 -42
- package/dist/application/javascript/JavaScriptArtifactGraphStructure.js +92 -10
- package/dist/application/javascript/JavaScriptArtifactPathResolution.js +293 -238
- package/dist/application/javascript/JavaScriptArtifactReconstruction.js +120 -28
- package/dist/application/javascript/JavaScriptArtifactReconstructionInput.js +4 -0
- package/dist/application/javascript/JavaScriptJsonModules.js +2 -2
- package/dist/application/javascript/JavaScriptModuleRelationships.js +10 -20
- package/dist/application/javascript/JavaScriptRecoveryService.js +3 -0
- package/dist/application/javascript/JavaScriptRuntimeReconciliationService.js +11 -27
- package/dist/application/javascript/JavaScriptSemanticGraphAsyncProjection.js +11 -5
- package/dist/application/javascript/JavaScriptSemanticGraphBuilder.js +206 -66
- package/dist/application/javascript/JavaScriptSemanticGraphChildProcessProjection.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphConstruction.js +18 -23
- package/dist/application/javascript/JavaScriptSemanticGraphDataProjection.js +5 -2
- package/dist/application/javascript/JavaScriptSemanticGraphEvidence.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphFingerprintProjection.js +2 -2
- package/dist/application/javascript/JavaScriptSemanticGraphFlowProjection.js +7 -5
- package/dist/application/javascript/JavaScriptSemanticGraphObjectProjection.js +6 -4
- package/dist/application/javascript/JavaScriptSemanticGraphProjection.js +4 -4
- package/dist/application/javascript/JavaScriptSemanticGraphResourceProjection.js +1 -1
- package/dist/application/javascript/JavaScriptSemanticGraphValueProjection.js +29 -15
- package/dist/application/javascript/JavaScriptSemanticTraceService.js +15 -10
- 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/NativeCallRoutes.js +2 -4
- 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 +34 -31
- package/dist/artifacts/ArtifactProviderMetadata.js +1 -4
- package/dist/artifacts/ArtifactReader.js +23 -0
- package/dist/artifacts/ArtifactResourceScope.js +100 -0
- package/dist/artifacts/AsarArtifactReader.js +218 -80
- 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 +179 -87
- package/dist/artifacts/NativeDmgOwnership.js +109 -0
- 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 +76 -49
- package/dist/artifacts/apple/MachoLoadCommandReader.js +36 -6
- package/dist/artifacts/extraction/ArtifactExtraction.js +134 -92
- package/dist/artifacts/inventory/ArtifactGraphConstruction.js +116 -50
- package/dist/artifacts/inventory/ArtifactInventory.js +5 -4
- package/dist/artifacts/inventory/classify.js +87 -25
- package/dist/artifacts/inventory/hashStableRootArtifact.js +70 -0
- package/dist/artifacts/inventory/reader.js +13 -5
- package/dist/artifacts/inventory/scanCanonical.js +73 -30
- package/dist/artifacts/inventory/scanReader.js +43 -20
- package/dist/artifacts/javascript/JavaScriptArtifactFiles.js +72 -28
- 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 +9 -3
- 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/CdpCaptureStorageFingerprints.js +3 -3
- package/dist/browser/CdpConnection.js +22 -5
- package/dist/browser/CdpElectronInspection.js +2 -2
- package/dist/browser/CdpElectronProvider.js +4 -3
- package/dist/browser/CdpElectronScripts.js +2 -2
- package/dist/browser/CdpPageCapture.js +1 -1
- package/dist/browser/CdpTargetSession.js +30 -34
- package/dist/browser/CdpWebMcpDiscovery.js +48 -23
- package/dist/browser/ElectronFileScope.js +99 -9
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +63 -7
- package/dist/browser/PlaywrightElectronActiveProvider.js +11 -6
- package/dist/browser/PlaywrightScenarioArtifacts.js +5 -5
- package/dist/browser/PlaywrightScenarioBrowser.js +208 -43
- package/dist/browser/PlaywrightScenarioSession.js +130 -65
- package/dist/browser/PlaywrightScenarioStorage.js +507 -0
- package/dist/browser/PngVisualDiff.js +198 -29
- package/dist/browser/WebSourceMapFetcher.js +35 -9
- package/dist/browser/assets/LocalWebScriptArtifacts.js +3 -1
- package/dist/browser/assets/PublishWebScripts.js +75 -20
- package/dist/browser/assets/ScenarioScriptCapture.js +8 -12
- 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/coreAnalysisCommands.js +2 -2
- package/dist/cli/coreBinaryCommands.js +12 -13
- package/dist/cli/coreNativeCommands.js +1 -14
- package/dist/cli/electronCommands.js +14 -10
- package/dist/cli/evmCommands.js +13 -4
- package/dist/cli/firmwareCommands.js +7 -2
- package/dist/cli/javascriptApplicationAnalysis.js +19 -13
- package/dist/cli/javascriptRecoveryCommands.js +22 -15
- package/dist/cli/jebCommands.js +99 -0
- package/dist/cli/jsonOutput.js +12 -4
- package/dist/cli/referenceSourceImportStatus.js +7 -0
- package/dist/cli/setupCommands.js +15 -3
- package/dist/cli/streamedJsonOutput.js +83 -4
- package/dist/cli/utilityCommands.js +68 -22
- package/dist/cli/webScriptCommands.js +20 -1
- package/dist/cli/webSourceLocationCommands.js +21 -9
- package/dist/cli.js +11 -2
- package/dist/cliBrowserScenarioCommands.js +2 -1
- package/dist/cliCommandNames.js +32 -0
- package/dist/cliJsonInput.js +47 -34
- package/dist/cliObservationOptions.js +7 -0
- package/dist/composition/adb.js +3 -0
- package/dist/composition/apktool.js +3 -0
- package/dist/composition/auxiliaryAnalysisProviders.js +5 -4
- package/dist/composition/binaryDiagnostics.js +4 -0
- package/dist/composition/browserScenario.js +2 -2
- package/dist/composition/directAnalysis.js +14 -7
- 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/artifactComparisonExample.js +5 -5
- package/dist/contracts/artifactToolContracts.js +8 -5
- package/dist/contracts/browserToolContracts.js +1 -1
- package/dist/contracts/compactInputSchema.js +256 -0
- package/dist/contracts/errorSchemas.js +3 -1
- package/dist/contracts/functionComparisonExample.js +8 -0
- package/dist/contracts/functionWorkflowToolContracts.js +1 -1
- package/dist/contracts/inputSchemaPresentation.js +104 -13
- package/dist/contracts/javascript/electronToolContracts.js +16 -3
- package/dist/contracts/javascript/javascriptApplicationWorkflowExamples.js +3 -2
- package/dist/contracts/javascript/javascriptExportShapeComparisonExample.js +6 -3
- package/dist/contracts/javascript/javascriptRecoveryToolContracts.js +1 -1
- package/dist/contracts/javascript/javascriptRuntimeReconciliationExample.js +8 -7
- package/dist/contracts/jeb/jebToolContracts.js +64 -0
- package/dist/contracts/managed/managedToolContracts.js +3 -2
- package/dist/contracts/mobileApplicationGraphExamples.js +5 -5
- package/dist/contracts/native/binaryDiagnosticsToolContracts.js +25 -3
- package/dist/contracts/native/nativeToolContracts.js +1 -1
- package/dist/contracts/officialToolContracts.js +5 -5
- package/dist/contracts/sessionLifecycleInputs.js +4 -3
- package/dist/contracts/sessionStatusContract.js +3 -2
- package/dist/contracts/sessionToolContracts.js +5 -4
- package/dist/contracts/sessionToolSchemas.js +9 -4
- 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 +7 -5
- package/dist/contracts/toolOutputSchemaPrimitives.js +2 -5
- package/dist/contracts/toolSchemaMetadata.js +82 -7
- package/dist/domain/adb/adbDeviceAnalysis.js +583 -0
- package/dist/domain/analysisErrorBase.js +5 -0
- package/dist/domain/analysisErrorCleanup.js +29 -0
- package/dist/domain/analysisErrorPresentation.js +18 -4
- package/dist/domain/analysisErrorProjection.js +4 -1
- package/dist/domain/analysisSnapshot.js +5 -2
- package/dist/domain/analysisView/analysisView.js +53 -5
- 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/android/androidPartialObservation.js +36 -0
- 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 +3 -3
- package/dist/domain/apple/interfaceBuilderGraph.js +22 -19
- package/dist/domain/apple/interfaceBuilderKeyedArchive.js +10 -1
- package/dist/domain/artifactComparison.js +39 -11
- package/dist/domain/artifactGraph.js +6 -4
- package/dist/domain/artifactIdentity.js +37 -9
- package/dist/domain/artifactInspection.js +10 -50
- package/dist/domain/artifactIntegrityPolicy.js +10 -0
- package/dist/domain/artifactInventoryEvidence.js +16 -17
- package/dist/domain/artifactPathSyntax.js +1 -1
- package/dist/domain/binaryTarget.js +16 -0
- package/dist/domain/binaryTargetTypes.js +8 -1
- package/dist/domain/browserCompleteness.js +3 -2
- package/dist/domain/browserObservationSchemas.js +8 -4
- package/dist/domain/browserScenarioCaptureValues.js +2 -2
- package/dist/domain/browserScenarioNormalization.js +3 -3
- package/dist/domain/browserScenarioValues.js +3 -2
- package/dist/domain/callPath.js +8 -10
- package/dist/domain/canonicalDigest.js +7 -1
- package/dist/domain/canonicalJsonDigestSteps.js +34 -12
- package/dist/domain/canonicalOrdering.js +1 -13
- package/dist/domain/changedBehavior.js +2 -3
- package/dist/domain/compactStringIdentity.js +9 -0
- package/dist/domain/comparisonSemantics.js +0 -5
- package/dist/domain/digests.js +0 -3
- package/dist/domain/evidence.js +12 -6
- package/dist/domain/evidenceBundle.js +51 -33
- package/dist/domain/evidenceRecordSummary.js +144 -0
- package/dist/domain/firmware/firmwareAnalysis.js +4 -3
- package/dist/domain/functionComparison.js +2 -1
- package/dist/domain/functionComparisonNormalization.js +4 -3
- package/dist/domain/functionComparisonResults.js +2 -2
- package/dist/domain/functionDossierEvidence.js +2 -1
- package/dist/domain/hopperValues.js +11 -15
- package/dist/domain/inputIssueProjection.js +16 -1
- package/dist/domain/javascript/electronActiveObservation.js +4 -3
- package/dist/domain/javascript/electronStaticAnalysisBrowser.js +14 -15
- package/dist/domain/javascript/electronStaticAnalysisIpc.js +20 -21
- package/dist/domain/javascript/electronStaticAnalysisNative.js +73 -41
- package/dist/domain/javascript/electronStaticAnalysisValues.js +24 -4
- package/dist/domain/javascript/javascriptAnalysisResourceControls.js +45 -0
- package/dist/domain/javascript/javascriptApplicationAnalysis.js +6 -1
- package/dist/domain/javascript/javascriptApplicationChangeGraph.js +18 -14
- package/dist/domain/javascript/javascriptApplicationEvidenceSchemas.js +4 -0
- package/dist/domain/javascript/javascriptApplicationGraph.js +91 -28
- package/dist/domain/javascript/javascriptApplicationProjectionResources.js +35 -0
- package/dist/domain/javascript/javascriptApplicationVersionComparison.js +4 -4
- package/dist/domain/javascript/javascriptApplicationVersionComparisonSchemas.js +37 -22
- package/dist/domain/javascript/javascriptApplicationVersionItems.js +72 -45
- package/dist/domain/javascript/javascriptApplicationVersionKeys.js +16 -8
- package/dist/domain/javascript/javascriptAstFingerprint.js +60 -33
- package/dist/domain/javascript/javascriptAstValues.js +54 -0
- package/dist/domain/javascript/javascriptElectronMemberWrites.js +50 -0
- package/dist/domain/javascript/javascriptExportShapeComparison.js +3 -2
- package/dist/domain/javascript/javascriptExportShapeComparisonSchemas.js +31 -23
- package/dist/domain/javascript/javascriptExportShapeSelection.js +2 -2
- package/dist/domain/javascript/javascriptExportShapeVariants.js +3 -2
- package/dist/domain/javascript/javascriptFeatureSeed.js +5 -3
- package/dist/domain/javascript/javascriptFeatureTrace.js +7 -6
- package/dist/domain/javascript/javascriptFeatureTraceSchemas.js +17 -9
- package/dist/domain/javascript/javascriptFeatureTraversal.js +4 -4
- package/dist/domain/javascript/javascriptModuleSemanticIr.js +15 -0
- package/dist/domain/javascript/javascriptNativeHandoff.js +12 -7
- package/dist/domain/javascript/javascriptRpcEndpoints.js +253 -0
- package/dist/domain/javascript/javascriptRuntimeLoadState.js +1 -3
- package/dist/domain/javascript/javascriptRuntimeObservation.js +8 -5
- package/dist/domain/javascript/javascriptRuntimeReconciliation.js +12 -6
- package/dist/domain/javascript/javascriptRuntimeReconciliationActive.js +9 -8
- package/dist/domain/javascript/javascriptRuntimeReconciliationCaptureParsing.js +212 -0
- package/dist/domain/javascript/javascriptRuntimeReconciliationGraph.js +12 -6
- package/dist/domain/javascript/javascriptRuntimeReconciliationInputValidation.js +28 -0
- package/dist/domain/javascript/javascriptRuntimeReconciliationMatching.js +5 -5
- package/dist/domain/javascript/javascriptRuntimeReconciliationParsing.js +12 -223
- package/dist/domain/javascript/javascriptRuntimeReconciliationResult.js +2 -2
- package/dist/domain/javascript/javascriptRuntimeReconciliationRuntime.js +15 -4
- package/dist/domain/javascript/javascriptRuntimeReconciliationSchemas.js +2 -2
- package/dist/domain/javascript/javascriptRuntimeStaticCandidates.js +15 -17
- package/dist/domain/javascript/javascriptSemanticAnalysis.js +379 -30
- package/dist/domain/javascript/javascriptSemanticCallResolution.js +9 -7
- package/dist/domain/javascript/javascriptSemanticCallableResults.js +42 -0
- package/dist/domain/javascript/javascriptSemanticCalls.js +8 -1
- package/dist/domain/javascript/javascriptSemanticChildProcesses.js +2 -2
- package/dist/domain/javascript/javascriptSemanticCoverage.js +20 -0
- package/dist/domain/javascript/javascriptSemanticDataEffectHelpers.js +7 -9
- package/dist/domain/javascript/javascriptSemanticDataEffects.js +4 -11
- package/dist/domain/javascript/javascriptSemanticDerivedAnalysis.js +15 -4
- package/dist/domain/javascript/javascriptSemanticFileProjection.js +1 -0
- package/dist/domain/javascript/javascriptSemanticFingerprints.js +43 -42
- package/dist/domain/javascript/javascriptSemanticGraph.js +205 -52
- package/dist/domain/javascript/javascriptSemanticGraphSchemas.js +21 -11
- package/dist/domain/javascript/javascriptSemanticIr.js +0 -4
- package/dist/domain/javascript/javascriptSemanticIterationSources.js +139 -0
- package/dist/domain/javascript/javascriptSemanticMemberMutations.js +774 -136
- package/dist/domain/javascript/javascriptSemanticMutationInitializers.js +190 -0
- package/dist/domain/javascript/javascriptSemanticMutationValues.js +98 -41
- package/dist/domain/javascript/javascriptSemanticObjectReferences.js +381 -0
- package/dist/domain/javascript/javascriptSemanticObjects.js +9 -7
- package/dist/domain/javascript/javascriptSemanticPrimitives.js +7 -2
- package/dist/domain/javascript/javascriptSemanticProjection.js +72 -28
- package/dist/domain/javascript/javascriptSemanticPromises.js +15 -21
- package/dist/domain/javascript/javascriptSemanticPropertyPaths.js +100 -0
- package/dist/domain/javascript/javascriptSemanticProvenance.js +3 -3
- package/dist/domain/javascript/javascriptSemanticQuery.js +33 -29
- package/dist/domain/javascript/javascriptSemanticQueryIdentity.js +4 -5
- package/dist/domain/javascript/javascriptSemanticQuerySchemas.js +8 -9
- package/dist/domain/javascript/javascriptSemanticRequireOrigin.js +16 -10
- package/dist/domain/javascript/javascriptSemanticReturnedReferences.js +219 -0
- package/dist/domain/javascript/javascriptSemanticReturns.js +34 -48
- package/dist/domain/javascript/javascriptSemanticState.js +22 -2
- package/dist/domain/javascript/javascriptSemanticTraversal.js +25 -2
- package/dist/domain/javascript/javascriptSemanticValues.js +169 -30
- package/dist/domain/javascript/javascriptSourceAnalysis.js +1 -0
- package/dist/domain/javascript/javascriptSourceMapPaths.js +11 -1
- package/dist/domain/javascript/javascriptSourceParser.js +34 -9
- package/dist/domain/javascript/javascriptStaticAnalysis.js +29 -17
- package/dist/domain/javascript/javascriptStaticAnalysisBundler.js +13 -12
- package/dist/domain/javascript/javascriptStaticAnalysisCalls.js +49 -5
- package/dist/domain/javascript/javascriptStaticAnalysisFindings.js +8 -4
- package/dist/domain/javascript/javascriptStaticAnalysisHelpers.js +26 -15
- package/dist/domain/javascript/javascriptStaticAnalysisState.js +1 -0
- package/dist/domain/javascript/sourceToBundleComparison.js +7 -5
- package/dist/domain/javascript/sourceToBundleSignals.js +7 -7
- package/dist/domain/jeb/jebAnalysis.js +114 -0
- package/dist/domain/jsonSerialization.js +109 -55
- package/dist/domain/jsonShape.js +69 -31
- package/dist/domain/jsonValue.js +3 -0
- package/dist/domain/localPath.js +10 -4
- package/dist/domain/managed/managedApplicationGraph.js +47 -6
- package/dist/domain/managed/managedApplicationGraphCoverage.js +8 -2
- package/dist/domain/managed/managedApplicationGraphNodes.js +94 -59
- package/dist/domain/managed/managedArtifact.js +1 -0
- package/dist/domain/managed/managedInspectionEvidence.js +13 -0
- package/dist/domain/managed/managedMemberComparisonMatch.js +6 -7
- package/dist/domain/native/nativeAotPe.js +1408 -0
- package/dist/domain/native/nativeCallObservation.js +2 -4
- package/dist/domain/native/nativeInstruction.js +21 -0
- package/dist/domain/native/nativeMetadataRecovery.js +79 -6
- package/dist/domain/native/nativeValueFlow.js +5 -11
- package/dist/domain/native/objcSwiftMetadata.js +15 -17
- package/dist/domain/native/peResources.js +94 -0
- package/dist/domain/nativeConvention.js +33 -0
- package/dist/domain/process/processCapture.js +102 -11
- package/dist/domain/process/processCaptureCoverage.js +8 -5
- package/dist/domain/process/processCaptureExample.js +67 -0
- package/dist/domain/process/processCaptureValidation.js +83 -3
- package/dist/domain/process/processComparison.js +0 -23
- package/dist/domain/process/processScenario.js +62 -10
- package/dist/domain/process/processTraceEvaluation.js +4 -4
- package/dist/domain/process/processTraceSpecification.js +1 -3
- package/dist/domain/propertyListKeys.js +3 -1
- package/dist/domain/providerCleanupError.js +6 -2
- package/dist/domain/reconstructionCoverage.js +2 -1
- package/dist/domain/reconstructionUnknowns.js +4 -3
- package/dist/domain/reconstructionVerification.js +3 -2
- package/dist/domain/referenceSourceGraph.js +32 -23
- package/dist/domain/referenceSourceImportParsing.js +40 -48
- package/dist/domain/referenceSourcePathIdentity.js +22 -0
- package/dist/domain/referenceSourceRequireBindings.js +137 -0
- package/dist/domain/residualUnknown.js +3 -2
- package/dist/domain/staticRuntimeCorrelation.js +2 -1
- package/dist/domain/swiftSymbolClassification.js +6 -1
- package/dist/domain/symbolAnalysis.js +17 -2
- package/dist/domain/unicodeCodePointOrder.js +6 -0
- package/dist/domain/webBundleAnalyzerInspection.js +23 -3
- package/dist/domain/webCaptureDiff.js +170 -30
- package/dist/domain/webCaptureDiffSchemas.js +2 -8
- package/dist/domain/webInventory.js +3 -2
- package/dist/domain/webMcpDiscovery.js +4 -3
- package/dist/domain/webScriptExport.js +1 -1
- 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 +5 -4
- 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 +65 -31
- package/dist/dotnet/ManagedStaticProviderMetadata.js +1 -4
- 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 +73 -0
- 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 +90 -8
- package/dist/ghidra/GhidraDiagnostics.js +11 -8
- package/dist/ghidra/GhidraFunctionValues.js +26 -2
- package/dist/ghidra/GhidraInstallation.js +111 -10
- package/dist/ghidra/GhidraInventoryValues.js +23 -1
- package/dist/ghidra/GhidraLanguageCatalog.js +99 -0
- package/dist/ghidra/GhidraLauncher.js +123 -58
- 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/HopperCleanup.js +1 -1
- 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 +10 -2
- package/dist/ida/IdaProvider.js +7 -0
- package/dist/ida/IdaSessionClient.js +7 -3
- package/dist/ida/IdaWorkspace.js +4 -2
- package/dist/inspector/JavaScriptRuntimeScope.js +9 -5
- package/dist/inspector/V8InspectorCaptureProjection.js +46 -13
- package/dist/inspector/V8InspectorProvider.js +60 -8
- 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/main/shutdown.js +76 -32
- package/dist/main/transport.js +1 -1
- 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/AppleObjcDispatchFacets.js +3 -3
- package/dist/native/AppleObjcProperties.js +17 -7
- package/dist/native/LldbCallTracer.js +241 -75
- package/dist/native/NativeMacOSProvider.js +100 -20
- package/dist/native/NativeMacOSProviderMetadata.js +1 -2
- 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 +104 -51
- 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 +116 -22
- package/dist/process/capture/ProcessCaptureLifecycle.js +363 -86
- package/dist/process/capture/ProcessCaptureProgress.js +62 -0
- package/dist/process/capture/ProcessFilesystemEffects.js +19 -4
- package/dist/process/capture/ProcessHarness.js +202 -47
- 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/analysisAdmission.js +8 -0
- package/dist/server/contractToolHandler.js +21 -0
- package/dist/server/createServer.js +118 -47
- 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 +6 -7
- 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/helpers.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/registerArtifactTools.js +2 -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 +36 -5
- package/dist/server/registerElectronTools.js +28 -10
- package/dist/server/registerEnhancedTools.js +78 -73
- package/dist/server/registerEvidenceTools.js +54 -46
- 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/registerManagedTools.js +7 -4
- 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/registerOfficialTools.js +31 -25
- 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 +58 -21
- 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 +38 -7
- 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 +31 -1
- package/dist/artifacts/inventory/policy.js +0 -2
- package/dist/domain/managed/managedApplicationGraphNodeCoverage.js +0 -6
- package/dist/server/registerNativeTools.js +0 -6
|
@@ -1,15 +1,31 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { mkdir, open, readdir, realpath, } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
import { OwnedFileHandle } from "../filesystem/OwnedFileHandle.js";
|
|
5
6
|
import { streamChunkToBuffer } from "./StreamBytes.js";
|
|
6
|
-
import { ArtifactPathRegistry, normalizeArtifactPath, } from "./ArtifactPaths.js";
|
|
7
|
+
import { ArtifactPathRegistry, destinationCaseCollisionMessage, normalizeArtifactPath, } from "./ArtifactPaths.js";
|
|
7
8
|
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
|
8
|
-
|
|
9
|
+
import { SafeOutputTreeCreationFailure } from "./SafeOutputTreeCreationFailure.js";
|
|
10
|
+
import { hashOutputFile } from "./SafeOutputTreeReadback.js";
|
|
11
|
+
import { removeOwnedTree } from "./SafeOutputTreeCleanup.js";
|
|
12
|
+
import { assertHandleIdentity, assertFilePathIdentity, assertPathIdentity, isAbsent, readDirectoryIdentity, readFileIdentity, replacedDirectory, } from "./SafeOutputTreeIdentity.js";
|
|
13
|
+
/**
|
|
14
|
+
* Materialize files in a tree created by this operation.
|
|
15
|
+
*
|
|
16
|
+
* Path identities are revalidated around operations, but Node has no portable
|
|
17
|
+
* descriptor-relative traversal; a syscall-boundary pathname race remains.
|
|
18
|
+
*/
|
|
9
19
|
export class SafeOutputTree {
|
|
10
20
|
platform;
|
|
11
21
|
#registry = new ArtifactPathRegistry();
|
|
12
22
|
#outputRoot;
|
|
23
|
+
#rootIdentity;
|
|
24
|
+
#nestedDirectories = new Map();
|
|
25
|
+
#unknownDirectories = new Set();
|
|
26
|
+
#ownedFiles = new Map();
|
|
27
|
+
#openFiles = new Map();
|
|
28
|
+
#openHandles = new Set();
|
|
13
29
|
#published = false;
|
|
14
30
|
#cleanup = {
|
|
15
31
|
status: "not-required",
|
|
@@ -41,102 +57,180 @@ export class SafeOutputTree {
|
|
|
41
57
|
throw new ArtifactReaderFailure("path", "Extraction output root already exists", { cause });
|
|
42
58
|
throw cause;
|
|
43
59
|
});
|
|
60
|
+
const tree = new SafeOutputTree(canonicalOutput, platform);
|
|
44
61
|
try {
|
|
62
|
+
const rootIdentity = await readDirectoryIdentity(canonicalOutput);
|
|
63
|
+
tree.#rootIdentity = rootIdentity;
|
|
45
64
|
if (platform !== "win32") {
|
|
46
|
-
const stagingHandle = await open(canonicalOutput, constants.O_RDONLY | constants.O_DIRECTORY);
|
|
65
|
+
const stagingHandle = tree.#trackHandle(await open(canonicalOutput, constants.O_RDONLY | constants.O_DIRECTORY));
|
|
66
|
+
let setup = { kind: "ready" };
|
|
47
67
|
try {
|
|
48
|
-
await stagingHandle.
|
|
68
|
+
await assertHandleIdentity(stagingHandle.handle, rootIdentity, canonicalOutput);
|
|
69
|
+
await stagingHandle.handle.chmod(0o700);
|
|
49
70
|
}
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
catch (cause) {
|
|
72
|
+
setup = { kind: "failed", cause };
|
|
52
73
|
}
|
|
74
|
+
try {
|
|
75
|
+
await tree.#closeHandle(stagingHandle);
|
|
76
|
+
}
|
|
77
|
+
catch (closeCause) {
|
|
78
|
+
if (setup.kind === "failed")
|
|
79
|
+
throw ArtifactReaderFailure.withCleanup(setup.cause, ArtifactReaderFailure.cleanupObservation(closeCause, canonicalOutput));
|
|
80
|
+
throw closeCause;
|
|
81
|
+
}
|
|
82
|
+
if (setup.kind === "failed")
|
|
83
|
+
throw setup.cause;
|
|
53
84
|
}
|
|
54
|
-
|
|
85
|
+
await assertPathIdentity(canonicalOutput, rootIdentity);
|
|
86
|
+
return tree;
|
|
55
87
|
}
|
|
56
88
|
catch (cause) {
|
|
57
|
-
|
|
58
|
-
throw cause;
|
|
89
|
+
throw new SafeOutputTreeCreationFailure(cause, tree);
|
|
59
90
|
}
|
|
60
91
|
}
|
|
61
92
|
get outputRoot() {
|
|
62
93
|
return this.#outputRoot;
|
|
63
94
|
}
|
|
95
|
+
/** The output was durably committed, even if descriptor cleanup later failed. */
|
|
96
|
+
get published() {
|
|
97
|
+
return this.#published;
|
|
98
|
+
}
|
|
64
99
|
get cleanup() {
|
|
65
100
|
return structuredClone(this.#cleanup);
|
|
66
101
|
}
|
|
67
102
|
/** Stream one regular file with exact byte and digest verification. */
|
|
68
|
-
async write(relativePath, source,
|
|
69
|
-
this.#assertWritable();
|
|
70
|
-
const path = normalizeArtifactPath(relativePath);
|
|
71
|
-
this.#registry.add(path, "file");
|
|
72
|
-
const destination = await this.#prepareParent(path);
|
|
73
|
-
const handle = await open(destination, constants.O_CREAT |
|
|
74
|
-
constants.O_EXCL |
|
|
75
|
-
constants.O_WRONLY |
|
|
76
|
-
constants.O_NOFOLLOW, 0o600).catch((cause) => {
|
|
77
|
-
throw new ArtifactReaderFailure("path", `Could not exclusively create extraction path: ${path}`, { cause });
|
|
78
|
-
});
|
|
79
|
-
const hash = createHash("sha256");
|
|
80
|
-
let bytes = 0;
|
|
103
|
+
async write(relativePath, source, expected, signal) {
|
|
81
104
|
try {
|
|
105
|
+
this.#assertWritable();
|
|
106
|
+
if (!Number.isSafeInteger(expected.bytes) || expected.bytes < 0)
|
|
107
|
+
throw new ArtifactReaderFailure("format", `Invalid expected extraction size for ${relativePath}`);
|
|
108
|
+
const path = normalizeDestinationPath(relativePath, this.platform);
|
|
109
|
+
this.#registry.add(path, "file");
|
|
110
|
+
const lineage = await this.#prepareParent(path);
|
|
111
|
+
const parent = lineage.at(-1);
|
|
112
|
+
if (parent === undefined)
|
|
113
|
+
throw replacedDirectory(this.#outputRoot);
|
|
114
|
+
const fileName = path.slice(path.lastIndexOf("/") + 1);
|
|
115
|
+
const destination = join(parent.path, fileName);
|
|
116
|
+
const handle = await open(destination, constants.O_CREAT |
|
|
117
|
+
constants.O_EXCL |
|
|
118
|
+
constants.O_WRONLY |
|
|
119
|
+
constants.O_NOFOLLOW, 0o600).catch(async (cause) => {
|
|
120
|
+
await throwIfDestinationCaseCollision(parent.path, path, cause);
|
|
121
|
+
throw new ArtifactReaderFailure("path", `Could not exclusively create extraction path: ${path}`, { cause });
|
|
122
|
+
});
|
|
123
|
+
const ownedHandle = this.#trackHandle(handle);
|
|
124
|
+
this.#openFiles.set(destination, ownedHandle);
|
|
125
|
+
const fileIdentity = await readFileIdentity(ownedHandle.handle, destination);
|
|
126
|
+
await assertFilePathIdentity(destination, fileIdentity);
|
|
127
|
+
this.#ownedFiles.set(destination, fileIdentity);
|
|
128
|
+
const hash = createHash("sha256");
|
|
129
|
+
let bytes = 0;
|
|
130
|
+
await this.#assertLineage(lineage);
|
|
82
131
|
for await (const raw of source) {
|
|
83
132
|
abortIfNeeded(signal);
|
|
84
133
|
const chunk = streamChunkToBuffer(raw);
|
|
134
|
+
if (chunk.length > expected.bytes - bytes)
|
|
135
|
+
throw new ArtifactReaderFailure("integrity", `Extracted content exceeds the inventoried size: ${path}`);
|
|
85
136
|
bytes += chunk.length;
|
|
86
137
|
hash.update(chunk);
|
|
87
|
-
await writeAll(handle, chunk);
|
|
138
|
+
await writeAll(ownedHandle.handle, chunk);
|
|
88
139
|
}
|
|
140
|
+
if (bytes !== expected.bytes)
|
|
141
|
+
throw new ArtifactReaderFailure("integrity", `Extracted content size disagrees with inventory: ${path}`);
|
|
89
142
|
const sha256 = hash.digest("hex");
|
|
90
|
-
if (sha256 !==
|
|
143
|
+
if (sha256 !== expected.sha256)
|
|
91
144
|
throw new ArtifactReaderFailure("integrity", `Extracted content disagrees with inventory: ${path}`);
|
|
92
|
-
await
|
|
93
|
-
await
|
|
94
|
-
|
|
145
|
+
await this.#assertLineage(lineage);
|
|
146
|
+
await assertFilePathIdentity(destination, fileIdentity);
|
|
147
|
+
await ownedHandle.handle.sync();
|
|
148
|
+
await this.#closeFileHandle(destination, ownedHandle);
|
|
149
|
+
const readbackHandle = this.#trackHandle(await open(destination, constants.O_RDONLY | constants.O_NOFOLLOW));
|
|
150
|
+
const readback = await hashOutputFile(readbackHandle, destination, fileIdentity, { maximum: bytes, signal });
|
|
151
|
+
await this.#closeHandle(readbackHandle);
|
|
152
|
+
await this.#assertLineage(lineage);
|
|
153
|
+
await assertFilePathIdentity(destination, fileIdentity);
|
|
95
154
|
if (readback.sha256 !== sha256 || readback.bytes !== bytes)
|
|
96
155
|
throw new ArtifactReaderFailure("integrity", `Durable readback verification failed: ${path}`);
|
|
97
156
|
return { relativePath: path, sha256, bytesWritten: bytes };
|
|
98
157
|
}
|
|
99
158
|
catch (cause) {
|
|
100
|
-
|
|
101
|
-
|
|
159
|
+
try {
|
|
160
|
+
source.destroy();
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// Preserve the write refusal or failure as the caller-visible error.
|
|
164
|
+
}
|
|
102
165
|
throw cause;
|
|
103
166
|
}
|
|
104
167
|
}
|
|
105
168
|
/** Sync the owned output tree and prevent further writes through this instance. */
|
|
106
169
|
async commit() {
|
|
107
170
|
this.#assertWritable();
|
|
171
|
+
await this.#assertOwnedDirectories();
|
|
108
172
|
// Windows has no directory fsync; file contents are already synced in write().
|
|
109
173
|
if (this.platform === "win32") {
|
|
110
174
|
this.#published = true;
|
|
111
175
|
return;
|
|
112
176
|
}
|
|
113
|
-
const parent = await open(dirname(this.#outputRoot), constants.O_RDONLY | constants.O_DIRECTORY);
|
|
177
|
+
const parent = this.#trackHandle(await open(dirname(this.#outputRoot), constants.O_RDONLY | constants.O_DIRECTORY));
|
|
114
178
|
let output;
|
|
179
|
+
let sync = { kind: "synced" };
|
|
115
180
|
try {
|
|
116
|
-
output = await open(this.#outputRoot, constants.O_RDONLY | constants.O_DIRECTORY);
|
|
117
|
-
await output.
|
|
118
|
-
await
|
|
181
|
+
output = this.#trackHandle(await open(this.#outputRoot, constants.O_RDONLY | constants.O_DIRECTORY));
|
|
182
|
+
await assertHandleIdentity(output.handle, this.#requireRootIdentity(), this.#outputRoot);
|
|
183
|
+
await output.handle.sync();
|
|
184
|
+
await parent.handle.sync();
|
|
119
185
|
this.#published = true;
|
|
120
186
|
}
|
|
121
187
|
catch (cause) {
|
|
122
|
-
|
|
188
|
+
sync = { kind: "failed", cause };
|
|
123
189
|
}
|
|
124
|
-
|
|
125
|
-
|
|
190
|
+
const closeResults = await Promise.allSettled([parent, output]
|
|
191
|
+
.filter(isDefined)
|
|
192
|
+
.map((handle) => this.#closeHandle(handle)));
|
|
193
|
+
const closeFailures = closeResults
|
|
194
|
+
.filter(isRejected)
|
|
195
|
+
.map(({ reason }) => reason);
|
|
196
|
+
if (closeFailures.length > 0) {
|
|
197
|
+
const closeFailure = new AggregateError(closeFailures, "Extraction output directory handles could not be closed");
|
|
198
|
+
const cleanup = ArtifactReaderFailure.cleanupObservation(closeFailure, this.#outputRoot);
|
|
199
|
+
if (sync.kind === "failed")
|
|
200
|
+
throw ArtifactReaderFailure.withCleanup(new ArtifactReaderFailure("path", "Could not durably sync extraction output", { cause: sync.cause }), cleanup);
|
|
201
|
+
throw ArtifactReaderFailure.withCleanup(closeFailure, cleanup);
|
|
126
202
|
}
|
|
203
|
+
if (sync.kind === "failed")
|
|
204
|
+
throw new ArtifactReaderFailure("path", "Could not durably sync extraction output", { cause: sync.cause });
|
|
127
205
|
}
|
|
128
206
|
/** Remove only this operation's unsealed tree and verify absence. */
|
|
129
207
|
async rollback() {
|
|
130
|
-
if (this.#published)
|
|
208
|
+
if (this.#published) {
|
|
209
|
+
await this.#closePendingHandles();
|
|
210
|
+
return structuredClone(this.#cleanup);
|
|
211
|
+
}
|
|
212
|
+
if (this.#cleanup.status === "complete")
|
|
131
213
|
return structuredClone(this.#cleanup);
|
|
214
|
+
this.#cleanup = {
|
|
215
|
+
status: "incomplete",
|
|
216
|
+
residualPaths: [basename(this.#outputRoot)],
|
|
217
|
+
};
|
|
132
218
|
let removalFailure;
|
|
133
219
|
try {
|
|
134
|
-
await
|
|
220
|
+
await this.#admitPendingFiles();
|
|
221
|
+
await this.#closePendingHandles();
|
|
222
|
+
await this.#assertOwnedDirectories();
|
|
223
|
+
await removeOwnedTree({
|
|
224
|
+
outputRoot: this.#outputRoot,
|
|
225
|
+
rootIdentity: this.#requireRootIdentity(),
|
|
226
|
+
directories: this.#nestedDirectories,
|
|
227
|
+
files: this.#ownedFiles,
|
|
228
|
+
});
|
|
135
229
|
}
|
|
136
230
|
catch (cause) {
|
|
137
231
|
removalFailure = cause;
|
|
138
232
|
}
|
|
139
|
-
const absent = await isAbsent(this.#outputRoot);
|
|
233
|
+
const absent = removalFailure === undefined && (await isAbsent(this.#outputRoot));
|
|
140
234
|
this.#cleanup = absent
|
|
141
235
|
? { status: "complete", residualPaths: [] }
|
|
142
236
|
: {
|
|
@@ -157,46 +251,117 @@ export class SafeOutputTree {
|
|
|
157
251
|
}
|
|
158
252
|
async #prepareParent(relativePath) {
|
|
159
253
|
const parts = relativePath.split("/");
|
|
160
|
-
|
|
161
|
-
if (fileName === undefined)
|
|
254
|
+
if (parts.pop() === undefined)
|
|
162
255
|
throw new ArtifactReaderFailure("path", "Invalid extraction path");
|
|
163
256
|
let current = this.#outputRoot;
|
|
257
|
+
let logicalParent = "";
|
|
258
|
+
const lineage = [
|
|
259
|
+
{ path: this.#outputRoot, identity: this.#requireRootIdentity() },
|
|
260
|
+
];
|
|
261
|
+
if (parts.length === 0)
|
|
262
|
+
await assertPathIdentity(this.#outputRoot, this.#requireRootIdentity());
|
|
164
263
|
for (const part of parts) {
|
|
264
|
+
const parent = lineage.at(-1);
|
|
265
|
+
if (parent === undefined)
|
|
266
|
+
throw replacedDirectory(this.#outputRoot);
|
|
267
|
+
const logicalPath = logicalParent.length === 0 ? part : `${logicalParent}/${part}`;
|
|
165
268
|
current = join(current, part);
|
|
269
|
+
await assertPathIdentity(parent.path, parent.identity);
|
|
270
|
+
let created = true;
|
|
166
271
|
await mkdir(current, { mode: 0o700 }).catch((cause) => {
|
|
167
272
|
if (!isAlreadyExists(cause))
|
|
168
273
|
throw cause;
|
|
274
|
+
created = false;
|
|
169
275
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
276
|
+
if (!created) {
|
|
277
|
+
await throwIfDestinationCaseCollision(parent.path, logicalPath);
|
|
278
|
+
const identity = this.#nestedDirectories.get(current);
|
|
279
|
+
if (identity === undefined)
|
|
280
|
+
throw replacedDirectory(current);
|
|
281
|
+
await assertPathIdentity(current, identity);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
try {
|
|
285
|
+
const identity = await readDirectoryIdentity(current);
|
|
286
|
+
this.#nestedDirectories.set(current, identity);
|
|
287
|
+
}
|
|
288
|
+
catch (cause) {
|
|
289
|
+
this.#unknownDirectories.add(current);
|
|
290
|
+
throw cause;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
await assertPathIdentity(parent.path, parent.identity);
|
|
294
|
+
const identity = this.#nestedDirectories.get(current);
|
|
295
|
+
if (identity === undefined)
|
|
296
|
+
throw replacedDirectory(current);
|
|
297
|
+
await assertPathIdentity(current, identity);
|
|
298
|
+
lineage.push({ path: current, identity });
|
|
299
|
+
logicalParent = logicalPath;
|
|
173
300
|
}
|
|
174
|
-
return
|
|
301
|
+
return lineage;
|
|
302
|
+
}
|
|
303
|
+
async #assertLineage(lineage) {
|
|
304
|
+
for (const { path, identity } of lineage)
|
|
305
|
+
await assertPathIdentity(path, identity);
|
|
306
|
+
}
|
|
307
|
+
async #assertOwnedDirectories() {
|
|
308
|
+
const rootIdentity = this.#requireRootIdentity();
|
|
309
|
+
await assertPathIdentity(this.#outputRoot, rootIdentity);
|
|
310
|
+
for (const [path, identity] of this.#nestedDirectories)
|
|
311
|
+
await assertPathIdentity(path, identity);
|
|
312
|
+
if (this.#unknownDirectories.size > 0)
|
|
313
|
+
throw new ArtifactReaderFailure("path", `Extraction directory ownership is unknown: ${[...this.#unknownDirectories].join(", ")}`);
|
|
314
|
+
}
|
|
315
|
+
#requireRootIdentity() {
|
|
316
|
+
if (this.#rootIdentity === undefined)
|
|
317
|
+
throw new ArtifactReaderFailure("path", `Extraction output root identity is unknown: ${this.#outputRoot}`);
|
|
318
|
+
return this.#rootIdentity;
|
|
175
319
|
}
|
|
176
320
|
#assertWritable() {
|
|
177
321
|
if (this.#published)
|
|
178
322
|
throw new ArtifactReaderFailure("integrity", "Extraction tree is already committed");
|
|
323
|
+
if (this.#cleanup.status !== "not-required")
|
|
324
|
+
throw new ArtifactReaderFailure("integrity", "Extraction tree cleanup has already started");
|
|
179
325
|
}
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
326
|
+
#trackHandle(handle) {
|
|
327
|
+
const owner = new OwnedFileHandle(handle);
|
|
328
|
+
this.#openHandles.add(owner);
|
|
329
|
+
return owner;
|
|
330
|
+
}
|
|
331
|
+
async #closeHandle(owner) {
|
|
332
|
+
await owner.close();
|
|
333
|
+
this.#openHandles.delete(owner);
|
|
334
|
+
}
|
|
335
|
+
async #closePendingHandles() {
|
|
336
|
+
const failures = [];
|
|
337
|
+
for (const owner of this.#openHandles) {
|
|
338
|
+
try {
|
|
339
|
+
await this.#closeHandle(owner);
|
|
340
|
+
}
|
|
341
|
+
catch (cause) {
|
|
342
|
+
failures.push(cause);
|
|
343
|
+
}
|
|
193
344
|
}
|
|
345
|
+
if (failures.length > 0)
|
|
346
|
+
throw new AggregateError(failures, "Output tree handles remain open");
|
|
194
347
|
}
|
|
195
|
-
|
|
196
|
-
await
|
|
348
|
+
async #closeFileHandle(path, owner) {
|
|
349
|
+
await this.#closeHandle(owner);
|
|
350
|
+
this.#openFiles.delete(path);
|
|
197
351
|
}
|
|
198
|
-
|
|
199
|
-
|
|
352
|
+
async #admitPendingFiles() {
|
|
353
|
+
for (const [path, owner] of this.#openFiles) {
|
|
354
|
+
let identity = this.#ownedFiles.get(path);
|
|
355
|
+
if (identity === undefined) {
|
|
356
|
+
identity = await readFileIdentity(owner.handle, path);
|
|
357
|
+
await assertFilePathIdentity(path, identity);
|
|
358
|
+
this.#ownedFiles.set(path, identity);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const isDefined = (value) => value !== undefined;
|
|
364
|
+
const isRejected = (result) => result.status === "rejected";
|
|
200
365
|
const writeAll = async (handle, chunk) => {
|
|
201
366
|
let offset = 0;
|
|
202
367
|
while (offset < chunk.length) {
|
|
@@ -206,14 +371,24 @@ const writeAll = async (handle, chunk) => {
|
|
|
206
371
|
offset += bytesWritten;
|
|
207
372
|
}
|
|
208
373
|
};
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const isAlreadyExists = (cause) => cause instanceof Error && "code" in cause && cause.code === "EEXIST";
|
|
374
|
+
const normalizeDestinationPath = (relativePath, platform) => {
|
|
375
|
+
const path = normalizeArtifactPath(relativePath);
|
|
376
|
+
if (platform === "win32" && path.includes(":"))
|
|
377
|
+
throw new ArtifactReaderFailure("path", `Windows destination cannot materialize artifact path as a regular file: ${path}; ':' denotes alternate data stream syntax.`);
|
|
378
|
+
return path;
|
|
379
|
+
};
|
|
216
380
|
const abortIfNeeded = (signal) => {
|
|
217
381
|
if (signal?.aborted === true)
|
|
218
382
|
throw new ArtifactReaderFailure("cancelled", "Artifact extraction cancelled");
|
|
219
383
|
};
|
|
384
|
+
const isAlreadyExists = (cause) => cause instanceof Error && "code" in cause && cause.code === "EEXIST";
|
|
385
|
+
/** Fail when this directory already holds another spelling of the requested segment. */
|
|
386
|
+
const throwIfDestinationCaseCollision = async (parentDirectory, logicalPath, cause) => {
|
|
387
|
+
const names = await readdir(parentDirectory).catch(() => undefined);
|
|
388
|
+
if (names === undefined)
|
|
389
|
+
return;
|
|
390
|
+
const message = destinationCaseCollisionMessage(logicalPath, names);
|
|
391
|
+
if (message === undefined)
|
|
392
|
+
return;
|
|
393
|
+
throw new ArtifactReaderFailure("path", message, cause === undefined ? undefined : { cause });
|
|
394
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readdir, rmdir, unlink } from "node:fs/promises";
|
|
2
|
+
import { dirname, sep } from "node:path";
|
|
3
|
+
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
|
4
|
+
import { assertFilePathIdentity, assertPathIdentity, replacedDirectory, } from "./SafeOutputTreeIdentity.js";
|
|
5
|
+
/** Remove only tracked files and empty directories, preserving successful progress. */
|
|
6
|
+
export const removeOwnedTree = async (input) => {
|
|
7
|
+
const { outputRoot, rootIdentity, directories, files } = input;
|
|
8
|
+
const filesByDirectory = new Map();
|
|
9
|
+
for (const entry of files) {
|
|
10
|
+
const directory = dirname(entry[0]);
|
|
11
|
+
const group = filesByDirectory.get(directory) ?? [];
|
|
12
|
+
group.push(entry);
|
|
13
|
+
filesByDirectory.set(directory, group);
|
|
14
|
+
}
|
|
15
|
+
const postorder = [...directories].sort(([left], [right]) => right.slice(outputRoot.length).split(sep).length -
|
|
16
|
+
left.slice(outputRoot.length).split(sep).length);
|
|
17
|
+
for (const [path, identity] of postorder) {
|
|
18
|
+
await removeFiles(path, identity, filesByDirectory.get(path) ?? [], files);
|
|
19
|
+
const parentPath = dirname(path);
|
|
20
|
+
const parentIdentity = parentPath === outputRoot ? rootIdentity : directories.get(parentPath);
|
|
21
|
+
if (parentIdentity === undefined)
|
|
22
|
+
throw replacedDirectory(parentPath);
|
|
23
|
+
await assertPathIdentity(parentPath, parentIdentity);
|
|
24
|
+
await assertPathIdentity(path, identity);
|
|
25
|
+
await requireEmpty(path);
|
|
26
|
+
await rmdir(path);
|
|
27
|
+
directories.delete(path);
|
|
28
|
+
}
|
|
29
|
+
await removeFiles(outputRoot, rootIdentity, filesByDirectory.get(outputRoot) ?? [], files);
|
|
30
|
+
await assertPathIdentity(outputRoot, rootIdentity);
|
|
31
|
+
await requireEmpty(outputRoot);
|
|
32
|
+
await rmdir(outputRoot);
|
|
33
|
+
};
|
|
34
|
+
const removeFiles = async (directory, identity, filesInDirectory, retainedFiles) => {
|
|
35
|
+
for (const [path, fileIdentity] of filesInDirectory) {
|
|
36
|
+
await assertPathIdentity(directory, identity);
|
|
37
|
+
await assertFilePathIdentity(path, fileIdentity);
|
|
38
|
+
await unlink(path);
|
|
39
|
+
retainedFiles.delete(path);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const requireEmpty = async (directory) => {
|
|
43
|
+
if ((await readdir(directory)).length > 0)
|
|
44
|
+
throw new ArtifactReaderFailure("path", `Unowned entries remain in extraction directory: ${directory}`);
|
|
45
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
|
2
|
+
/** Setup failed after this tree was acquired; callers still own this exact tree. */
|
|
3
|
+
export class SafeOutputTreeCreationFailure extends ArtifactReaderFailure {
|
|
4
|
+
tree;
|
|
5
|
+
constructor(cause, tree) {
|
|
6
|
+
const primary = cause instanceof ArtifactReaderFailure
|
|
7
|
+
? cause
|
|
8
|
+
: new ArtifactReaderFailure("io", errorMessage(cause), { cause });
|
|
9
|
+
super(primary.reason, primary.message, {
|
|
10
|
+
cause: primary,
|
|
11
|
+
...(primary.cleanup === undefined ? {} : { cleanup: primary.cleanup }),
|
|
12
|
+
...(primary.partialObservation === undefined
|
|
13
|
+
? {}
|
|
14
|
+
: { partialObservation: primary.partialObservation }),
|
|
15
|
+
}, primary.details);
|
|
16
|
+
this.name = "SafeOutputTreeCreationFailure";
|
|
17
|
+
this.tree = tree;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const errorMessage = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { lstat } from "node:fs/promises";
|
|
2
|
+
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
|
3
|
+
export const readDirectoryIdentity = async (path) => {
|
|
4
|
+
const metadata = await lstat(path, { bigint: true });
|
|
5
|
+
if (!metadata.isDirectory())
|
|
6
|
+
throw replacedDirectory(path);
|
|
7
|
+
return { dev: metadata.dev, ino: metadata.ino };
|
|
8
|
+
};
|
|
9
|
+
export const assertPathIdentity = async (path, expected) => {
|
|
10
|
+
const metadata = await lstat(path, { bigint: true });
|
|
11
|
+
if (!metadata.isDirectory() ||
|
|
12
|
+
metadata.dev !== expected.dev ||
|
|
13
|
+
metadata.ino !== expected.ino)
|
|
14
|
+
throw replacedDirectory(path);
|
|
15
|
+
};
|
|
16
|
+
export const assertHandleIdentity = async (handle, expected, path) => {
|
|
17
|
+
const metadata = await handle.stat({ bigint: true });
|
|
18
|
+
if (!metadata.isDirectory() ||
|
|
19
|
+
metadata.dev !== expected.dev ||
|
|
20
|
+
metadata.ino !== expected.ino)
|
|
21
|
+
throw replacedDirectory(path);
|
|
22
|
+
};
|
|
23
|
+
export const readFileIdentity = async (handle, path) => {
|
|
24
|
+
const metadata = await handle.stat({ bigint: true });
|
|
25
|
+
if (!metadata.isFile())
|
|
26
|
+
throw new ArtifactReaderFailure("path", `Extraction file identity changed: ${path}`);
|
|
27
|
+
return { dev: metadata.dev, ino: metadata.ino };
|
|
28
|
+
};
|
|
29
|
+
export const assertFilePathIdentity = async (path, expected) => {
|
|
30
|
+
const metadata = await lstat(path, { bigint: true });
|
|
31
|
+
if (!metadata.isFile() ||
|
|
32
|
+
metadata.dev !== expected.dev ||
|
|
33
|
+
metadata.ino !== expected.ino)
|
|
34
|
+
throw new ArtifactReaderFailure("path", `Extraction file identity changed: ${path}`);
|
|
35
|
+
};
|
|
36
|
+
export const isAbsent = async (path) => lstat(path).then(() => false, (cause) => {
|
|
37
|
+
if (isNotFound(cause))
|
|
38
|
+
return true;
|
|
39
|
+
throw cause;
|
|
40
|
+
});
|
|
41
|
+
export const replacedDirectory = (path) => new ArtifactReaderFailure("path", `Extraction directory identity changed: ${path}`);
|
|
42
|
+
const isNotFound = (cause) => cause instanceof Error && "code" in cause && cause.code === "ENOENT";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileHandleChunks } from "../filesystem/readFileHandleChunks.js";
|
|
3
|
+
import { streamChunkToBuffer } from "./StreamBytes.js";
|
|
4
|
+
import { ArtifactReaderFailure } from "./ArtifactReader.js";
|
|
5
|
+
import { assertFilePathIdentity, readFileIdentity, } from "./SafeOutputTreeIdentity.js";
|
|
6
|
+
/** Hash one retained readback descriptor and confirm it still names the output file. */
|
|
7
|
+
export const hashOutputFile = async (owner, path, identity, options) => {
|
|
8
|
+
const admittedIdentity = await readFileIdentity(owner.handle, path);
|
|
9
|
+
await assertFilePathIdentity(path, identity);
|
|
10
|
+
if (admittedIdentity.dev !== identity.dev ||
|
|
11
|
+
admittedIdentity.ino !== identity.ino)
|
|
12
|
+
throw new ArtifactReaderFailure("path", `Extraction file identity changed: ${path}`);
|
|
13
|
+
const hash = createHash("sha256");
|
|
14
|
+
let bytes = 0;
|
|
15
|
+
try {
|
|
16
|
+
for await (const raw of readFileHandleChunks(owner.handle, options)) {
|
|
17
|
+
if (options.signal?.aborted === true)
|
|
18
|
+
throw new ArtifactReaderFailure("cancelled", "Artifact extraction cancelled");
|
|
19
|
+
const chunk = streamChunkToBuffer(raw);
|
|
20
|
+
bytes += chunk.length;
|
|
21
|
+
if (bytes > options.maximum)
|
|
22
|
+
throw new ArtifactReaderFailure("integrity", "Readback exceeded the bytes written");
|
|
23
|
+
hash.update(chunk);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (cause) {
|
|
27
|
+
if (options.signal?.aborted === true)
|
|
28
|
+
throw new ArtifactReaderFailure("cancelled", "Artifact extraction cancelled", { cause });
|
|
29
|
+
throw cause;
|
|
30
|
+
}
|
|
31
|
+
await assertFilePathIdentity(path, identity);
|
|
32
|
+
return { sha256: hash.digest("hex"), bytes };
|
|
33
|
+
};
|