rea-agents 1.7.0 → 2.1.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 +112 -59
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +42 -2
- package/dist/application/ClientRegistrationStatus.js +1 -1
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +11 -29
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +165 -197
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +112 -0
- package/dist/application/ElectronBoundaryGraph.js +9 -0
- package/dist/application/ElectronBoundaryGraphContext.js +62 -0
- package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
- package/dist/application/ElectronBoundaryGraphNative.js +86 -0
- package/dist/application/ElectronBoundaryGraphWindows.js +223 -0
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +58 -50
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InvestigationProviders.js +30 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptApplicationEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
- package/dist/application/JavaScriptApplicationService.js +74 -0
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
- package/dist/application/JavaScriptArtifactAnalysis.js +52 -7
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +82 -17
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +4 -1
- package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayPlanning.js +201 -0
- package/dist/application/JavaScriptReplayService.js +292 -0
- package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
- package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/ManagedApplicationGraphService.js +55 -0
- package/dist/application/ManagedMemberComparisonService.js +122 -0
- package/dist/application/ManagedNativeVerificationService.js +39 -0
- package/dist/application/ManagedReconstructionService.js +58 -0
- package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProcessSampling.js +15 -11
- package/dist/application/ProjectPermissionStore.js +49 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +147 -259
- package/dist/application/SetupClientConfiguration.js +220 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +123 -12
- package/dist/application/SetupSkill.js +26 -12
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +6 -3
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/application/runtime.js +2 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +46 -464
- package/dist/browser/CdpElectronInspection.js +106 -162
- package/dist/browser/CdpElectronProvider.js +5 -1
- package/dist/browser/CdpElectronScriptEvents.js +69 -0
- package/dist/browser/CdpElectronScripts.js +94 -0
- package/dist/browser/CdpElectronWorkers.js +56 -0
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -129
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +8 -1
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +108 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +13 -383
- package/dist/cliApplicationCommands.js +176 -0
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +17 -0
- package/dist/cliElectronCommands.js +100 -27
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliJsonInput.js +54 -0
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +289 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -292
- package/dist/contracts/applicationToolContracts.js +225 -0
- package/dist/contracts/artifactToolContracts.js +5 -9
- package/dist/contracts/browserToolContracts.js +14 -62
- package/dist/contracts/electronToolContracts.js +45 -19
- package/dist/contracts/errorSchemas.js +1 -0
- package/dist/contracts/investigationExamples.js +0 -6
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
- package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
- package/dist/contracts/managedToolContracts.js +153 -0
- package/dist/contracts/managedWorkflowExamples.js +346 -0
- package/dist/contracts/managedWorkflowToolContracts.js +203 -0
- package/dist/contracts/nativeToolContracts.js +2 -6
- package/dist/contracts/promptContracts.js +18 -2
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/toolContractExamples.js +10 -25
- package/dist/contracts/toolContracts.js +49 -47
- package/dist/contracts/toolEffects.js +174 -0
- package/dist/contracts/toolOutputSchemaGroups.js +232 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
- package/dist/contracts/toolOutputSchemas.js +2 -535
- package/dist/doctorRuntime.js +42 -1
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/artifactComparison.js +37 -19
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/browserObservation.js +1 -282
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/bundleComparison.js +4 -4
- package/dist/domain/electronObservation.js +13 -0
- package/dist/domain/electronStaticAnalysis.js +9 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +206 -0
- package/dist/domain/electronStaticAnalysisIpc.js +171 -0
- package/dist/domain/electronStaticAnalysisNative.js +164 -0
- package/dist/domain/electronStaticAnalysisTypes.js +1 -0
- package/dist/domain/electronStaticAnalysisValues.js +103 -0
- package/dist/domain/errors.js +32 -448
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/functionComparisonSchemas.js +3 -8
- package/dist/domain/inputIssueProjection.js +52 -0
- package/dist/domain/javascriptApplicationAnalysis.js +155 -0
- package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
- package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
- package/dist/domain/javascriptApplicationGraph.js +2 -1
- package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
- package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
- package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
- package/dist/domain/javascriptApplicationVersionItems.js +233 -0
- package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureSeed.js +140 -0
- package/dist/domain/javascriptFeatureTrace.js +232 -0
- package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
- package/dist/domain/javascriptFeatureTraversal.js +100 -0
- package/dist/domain/javascriptNativeHandoff.js +85 -0
- package/dist/domain/javascriptReplay.js +361 -0
- package/dist/domain/javascriptRuntimeLoadState.js +106 -0
- package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
- package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
- package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
- package/dist/domain/javascriptRuntimeStaticCandidates.js +193 -0
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +26 -254
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +81 -2
- package/dist/domain/javascriptStaticAnalysisState.js +6 -0
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +206 -0
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +452 -0
- package/dist/domain/managedMemberComparison.js +211 -0
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +46 -0
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +196 -0
- package/dist/domain/managedRuntimeCorrelation.js +184 -0
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +9 -3
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +339 -0
- package/dist/dotnet/ManagedMemberInspector.js +153 -0
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
- package/dist/dotnet/ManagedMetadataInventory.js +104 -0
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +259 -0
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +143 -0
- package/dist/dotnet/ManagedPeReader.js +188 -0
- package/dist/dotnet/ManagedReaderFailure.js +10 -0
- package/dist/dotnet/ManagedStaticProvider.js +203 -0
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +67 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +3 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -132
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +300 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +217 -0
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/LinuxRuntimeClosure.js +46 -0
- package/dist/replay/LinuxSeccompPolicy.js +40 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/replay/ReplayWorkerProtocol.js +55 -0
- package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +158 -41
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +13 -0
- package/dist/server/registerArtifactComparisonTool.js +16 -9
- package/dist/server/registerBrowserTools.js +61 -60
- package/dist/server/registerBundleComparisonTool.js +17 -20
- package/dist/server/registerElectronTools.js +39 -12
- package/dist/server/registerEnhancedTools.js +52 -15
- package/dist/server/registerEvidenceResources.js +54 -0
- package/dist/server/registerEvidenceTools.js +5 -1
- package/dist/server/registerFunctionComparisonTool.js +14 -7
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +103 -132
- package/dist/server/registerManagedTools.js +6 -0
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +13 -0
- package/dist/server/registerOfficialTools.js +81 -67
- package/dist/server/registerProcessComparisonTool.js +25 -47
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +9 -8
- package/dist/server/registerSessionTools.js +77 -216
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/sessionEvidence.js +14 -19
- package/dist/server/toolInputValidation.js +77 -0
- package/dist/server/toolRegistrationOptions.js +177 -2
- package/dist/server/toolResult.js +30 -17
- package/package.json +21 -14
- package/scripts/rea.mjs +1 -1
- package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +75 -6
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
|
@@ -1,148 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createReadStream } from "node:fs";
|
|
3
|
-
import { lstat, open, realpath } from "node:fs/promises";
|
|
4
|
-
import { AsarArtifactReader } from "../artifacts/AsarArtifactReader.js";
|
|
5
|
-
import { ArtifactPathRegistry, normalizeArtifactPath, } from "../artifacts/ArtifactPaths.js";
|
|
6
|
-
import { ArtifactReaderFailure, } from "../artifacts/ArtifactReader.js";
|
|
7
|
-
import { DirectoryArtifactReader } from "../artifacts/DirectoryArtifactReader.js";
|
|
8
|
-
import { ZipArtifactReader } from "../artifacts/ZipArtifactReader.js";
|
|
9
|
-
import { MachOSliceArtifactReader } from "../artifacts/MachOSliceArtifactReader.js";
|
|
10
|
-
import { NativeDmgArtifactReader } from "../artifacts/NativeDmgArtifactReader.js";
|
|
11
|
-
import { streamChunkToBuffer } from "../artifacts/StreamBytes.js";
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
12
2
|
import { artifactInventoryResultSchema, } from "../domain/artifactGraph.js";
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
-
const STRICT_INTEGRITY_POLICY = {
|
|
19
|
-
mode: "fail",
|
|
20
|
-
approved: false,
|
|
21
|
-
enabled: false,
|
|
22
|
-
maxMismatches: 1,
|
|
23
|
-
};
|
|
3
|
+
import { pageOf } from "./ArtifactGraphConstruction.js";
|
|
4
|
+
import { abortIfNeeded } from "./ArtifactInventory/hash.js";
|
|
5
|
+
import { scanCanonicalArtifactInventory } from "./ArtifactInventory/scanCanonical.js";
|
|
6
|
+
export { scanCanonicalArtifactInventory } from "./ArtifactInventory/scanCanonical.js";
|
|
24
7
|
/** Inventory one local artifact without extracting or mounting it. */
|
|
25
8
|
export const inventoryArtifact = async (inputPath, limits, page, options = {}) => {
|
|
26
|
-
const snapshot = await scanArtifactInventory(inputPath, limits, options
|
|
9
|
+
const snapshot = await scanArtifactInventory(inputPath, limits, options);
|
|
27
10
|
return paginateArtifactInventory(snapshot, page);
|
|
28
11
|
};
|
|
29
12
|
/** Scan an artifact once and retain the complete immutable graph for projection. */
|
|
30
|
-
export const scanArtifactInventory = async (inputPath, limits,
|
|
31
|
-
abortIfNeeded(signal);
|
|
13
|
+
export const scanArtifactInventory = async (inputPath, limits, options = {}) => {
|
|
14
|
+
abortIfNeeded(options.signal);
|
|
32
15
|
const path = await realpath(inputPath);
|
|
33
|
-
return scanCanonicalArtifactInventory(path, limits,
|
|
34
|
-
};
|
|
35
|
-
/** Scan one already-canonical artifact path without resolving it again. */
|
|
36
|
-
export const scanCanonicalArtifactInventory = async (path, limits, signal, nativeMount = NATIVE_MOUNT_DISABLED, integrity = STRICT_INTEGRITY_POLICY) => {
|
|
37
|
-
if (integrity.mode === "record-and-continue" &&
|
|
38
|
-
(!integrity.approved || !integrity.enabled))
|
|
39
|
-
throw new ArtifactReaderFailure("unavailable", "Integrity continuation requires explicit approval and operator policy");
|
|
40
|
-
const metadata = await lstat(path);
|
|
41
|
-
const rootFormat = await classifyRoot(path, metadata.isDirectory());
|
|
42
|
-
const rootDigest = metadata.isDirectory()
|
|
43
|
-
? null
|
|
44
|
-
: await hashReadable(createReadStream(path), limits.maxTotalBytes, signal);
|
|
45
|
-
const reader = await createReader(path, rootFormat, nativeMount, signal);
|
|
46
|
-
try {
|
|
47
|
-
const { nodes, occurrences, pendingContradictions } = await scanReader(reader, limits, signal, integrity);
|
|
48
|
-
materializeDirectoryNodes(occurrences, nodes);
|
|
49
|
-
const rootNode = createRootNode({
|
|
50
|
-
path,
|
|
51
|
-
format: rootFormat,
|
|
52
|
-
directory: metadata.isDirectory(),
|
|
53
|
-
digest: rootDigest,
|
|
54
|
-
occurrences,
|
|
55
|
-
});
|
|
56
|
-
nodes.set(rootNode.artifact_id, rootNode);
|
|
57
|
-
rekeyOccurrences(rootNode.artifact_id, occurrences);
|
|
58
|
-
const rootOccurrence = rootOccurrenceFor(rootNode, metadata.size);
|
|
59
|
-
for (const occurrence of occurrences)
|
|
60
|
-
if (occurrence.parent_occurrence_id === null)
|
|
61
|
-
occurrence.parent_occurrence_id = rootOccurrence.occurrence_id;
|
|
62
|
-
occurrences.unshift(rootOccurrence);
|
|
63
|
-
const occurrenceById = new Map(occurrences.map((occurrence) => [occurrence.occurrence_id, occurrence]));
|
|
64
|
-
const occurrenceByPath = indexOccurrencesByPath(occurrences);
|
|
65
|
-
const integrityContradictions = pendingContradictions.map((contradiction) => {
|
|
66
|
-
const occurrence = occurrenceByPath.get(contradiction.logicalPath);
|
|
67
|
-
if (occurrence === undefined)
|
|
68
|
-
throw new ArtifactReaderFailure("integrity", "Integrity contradiction lost its graph occurrence");
|
|
69
|
-
const parent = occurrence.parent_occurrence_id === null
|
|
70
|
-
? undefined
|
|
71
|
-
: occurrenceById.get(occurrence.parent_occurrence_id);
|
|
72
|
-
const parentArtifactId = parent?.artifact_id ?? rootNode.artifact_id;
|
|
73
|
-
return {
|
|
74
|
-
contradiction_id: `ic_${digestCanonical({
|
|
75
|
-
root_artifact_id: rootNode.artifact_id,
|
|
76
|
-
logical_path: contradiction.logicalPath,
|
|
77
|
-
declared_sha256: contradiction.declaredSha256,
|
|
78
|
-
observed_sha256: contradiction.observedSha256,
|
|
79
|
-
})}`,
|
|
80
|
-
occurrence_id: occurrence.occurrence_id,
|
|
81
|
-
parent_artifact_id: parentArtifactId,
|
|
82
|
-
logical_path: contradiction.logicalPath,
|
|
83
|
-
declared_sha256: contradiction.declaredSha256,
|
|
84
|
-
observed_sha256: contradiction.observedSha256,
|
|
85
|
-
entry_kind: contradiction.entryKind,
|
|
86
|
-
unpacked: contradiction.unpacked,
|
|
87
|
-
trust: "observed-untrusted",
|
|
88
|
-
provenance: "container-integrity-metadata-versus-observed-bytes",
|
|
89
|
-
limitations: [
|
|
90
|
-
"Observed bytes contradict declared integrity metadata and cannot support equivalence.",
|
|
91
|
-
],
|
|
92
|
-
};
|
|
93
|
-
});
|
|
94
|
-
const edges = createArtifactEdges(rootNode.artifact_id, occurrences, reader?.provenance()[0]);
|
|
95
|
-
const orderedNodes = [...nodes.values()].sort((left, right) => left.artifact_id.localeCompare(right.artifact_id));
|
|
96
|
-
const orderedOccurrences = occurrences.sort((left, right) => left.logical_path.localeCompare(right.logical_path, "en"));
|
|
97
|
-
const orderedEdges = edges.sort((left, right) => left.edge_id.localeCompare(right.edge_id));
|
|
98
|
-
if (rootDigest !== null) {
|
|
99
|
-
const verified = await hashReadable(createReadStream(path), limits.maxTotalBytes, signal);
|
|
100
|
-
if (verified.sha256 !== rootDigest.sha256 ||
|
|
101
|
-
verified.bytes !== rootDigest.bytes)
|
|
102
|
-
throw new ArtifactReaderFailure("integrity", "Root artifact changed during inventory");
|
|
103
|
-
}
|
|
104
|
-
const graphSha256 = digestCanonical({
|
|
105
|
-
nodes: orderedNodes,
|
|
106
|
-
occurrences: orderedOccurrences,
|
|
107
|
-
edges: orderedEdges,
|
|
108
|
-
integrity_contradictions: integrityContradictions,
|
|
109
|
-
});
|
|
110
|
-
const manifestId = `agm_${digestCanonical({
|
|
111
|
-
schema_version: 1,
|
|
112
|
-
root_artifact_id: rootNode.artifact_id,
|
|
113
|
-
graph_sha256: graphSha256,
|
|
114
|
-
})}`;
|
|
115
|
-
return {
|
|
116
|
-
manifest: artifactInventoryResultSchema.shape.manifest.parse({
|
|
117
|
-
schema_version: 1,
|
|
118
|
-
manifest_id: manifestId,
|
|
119
|
-
root_artifact_id: rootNode.artifact_id,
|
|
120
|
-
root_sha256: rootNode.sha256,
|
|
121
|
-
root_format: rootNode.format,
|
|
122
|
-
graph_sha256: graphSha256,
|
|
123
|
-
node_count: orderedNodes.length,
|
|
124
|
-
occurrence_count: orderedOccurrences.length,
|
|
125
|
-
edge_count: orderedEdges.length,
|
|
126
|
-
}),
|
|
127
|
-
nodes: orderedNodes,
|
|
128
|
-
occurrences: orderedOccurrences,
|
|
129
|
-
edges: orderedEdges,
|
|
130
|
-
limits: toOutputLimits(limits),
|
|
131
|
-
provenance: reader?.provenance() ?? [],
|
|
132
|
-
integrity_contradictions: integrityContradictions,
|
|
133
|
-
limitations: [
|
|
134
|
-
...inventoryLimitations(rootFormat, reader),
|
|
135
|
-
...(integrityContradictions.length === 0
|
|
136
|
-
? []
|
|
137
|
-
: [
|
|
138
|
-
`${String(integrityContradictions.length)} integrity contradiction(s) were recorded; mismatched content is observed-untrusted.`,
|
|
139
|
-
]),
|
|
140
|
-
],
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
finally {
|
|
144
|
-
await reader?.close();
|
|
145
|
-
}
|
|
16
|
+
return scanCanonicalArtifactInventory(path, limits, options);
|
|
146
17
|
};
|
|
147
18
|
/** Project independently paged graph collections from one inventory snapshot. */
|
|
148
19
|
export const paginateArtifactInventory = (snapshot, page) => artifactInventoryResultSchema.parse({
|
|
@@ -151,216 +22,3 @@ export const paginateArtifactInventory = (snapshot, page) => artifactInventoryRe
|
|
|
151
22
|
occurrences: pageOf(snapshot.occurrences, page.occurrenceOffset, page.occurrenceLimit),
|
|
152
23
|
edges: pageOf(snapshot.edges, page.edgeOffset, page.edgeLimit),
|
|
153
24
|
});
|
|
154
|
-
const inventoryLimitations = (format, reader) => {
|
|
155
|
-
if (reader !== undefined)
|
|
156
|
-
return [];
|
|
157
|
-
if (format === "dmg" || format === "pkg")
|
|
158
|
-
return [
|
|
159
|
-
`${format.toUpperCase()} root hash is observed; child inventory requires an approved native macOS adapter.`,
|
|
160
|
-
];
|
|
161
|
-
if (format === "mach-o-universal" && process.platform !== "darwin")
|
|
162
|
-
return ["Universal Mach-O slices require the native macOS lipo adapter."];
|
|
163
|
-
return ["Artifact has no child container entries."];
|
|
164
|
-
};
|
|
165
|
-
const createReader = async (path, format, nativeMount, signal) => {
|
|
166
|
-
switch (format) {
|
|
167
|
-
case "directory":
|
|
168
|
-
return new DirectoryArtifactReader(path);
|
|
169
|
-
case "zip":
|
|
170
|
-
case "ipa":
|
|
171
|
-
case "apk":
|
|
172
|
-
return new ZipArtifactReader(path, format);
|
|
173
|
-
case "asar":
|
|
174
|
-
return new AsarArtifactReader(path);
|
|
175
|
-
case "mach-o-universal":
|
|
176
|
-
return process.platform === "darwin"
|
|
177
|
-
? new MachOSliceArtifactReader(path)
|
|
178
|
-
: undefined;
|
|
179
|
-
case "dmg":
|
|
180
|
-
if (!nativeMount.nativeMountApproved)
|
|
181
|
-
return undefined;
|
|
182
|
-
if (!nativeMount.nativeMountEnabled)
|
|
183
|
-
throw new ArtifactReaderFailure("unavailable", "Native DMG mounting is disabled by operator policy");
|
|
184
|
-
return NativeDmgArtifactReader.create(path, signal);
|
|
185
|
-
default:
|
|
186
|
-
return undefined;
|
|
187
|
-
}
|
|
188
|
-
};
|
|
189
|
-
const visitNestedAsar = async (adapterKey, logicalPath, visit) => {
|
|
190
|
-
const nested = new AsarArtifactReader(adapterKey);
|
|
191
|
-
try {
|
|
192
|
-
await visit(nested, logicalPath);
|
|
193
|
-
}
|
|
194
|
-
finally {
|
|
195
|
-
await nested.close();
|
|
196
|
-
}
|
|
197
|
-
};
|
|
198
|
-
const isExpandableAsar = (entry, logicalPath) => entry.kind === "file" &&
|
|
199
|
-
logicalPath.toLowerCase().endsWith(".asar") &&
|
|
200
|
-
entry.adapterKey.startsWith("/");
|
|
201
|
-
const emptyScan = () => ({ nodes: new Map(), occurrences: [], pendingContradictions: [] });
|
|
202
|
-
const scanReader = async (reader, limits, signal, integrity = STRICT_INTEGRITY_POLICY) => {
|
|
203
|
-
const { nodes, occurrences, pendingContradictions } = emptyScan();
|
|
204
|
-
if (reader === undefined)
|
|
205
|
-
return { nodes, occurrences, pendingContradictions };
|
|
206
|
-
const occurrenceByPath = new Map();
|
|
207
|
-
const registry = new ArtifactPathRegistry();
|
|
208
|
-
let totalBytes = 0;
|
|
209
|
-
const digestEntry = async (currentReader, entry, logicalPath) => {
|
|
210
|
-
if ((entry.kind !== "file" && entry.kind !== "slice") || entry.encrypted)
|
|
211
|
-
return undefined;
|
|
212
|
-
const remainingBytes = limits.maxTotalBytes - totalBytes;
|
|
213
|
-
if (remainingBytes <= 0)
|
|
214
|
-
throw new ArtifactReaderFailure("limit", "Artifact total byte limit exceeded");
|
|
215
|
-
if (entry.declaredSize !== null && entry.declaredSize > remainingBytes)
|
|
216
|
-
throw new ArtifactReaderFailure("limit", "Declared artifact bytes exceed remaining cumulative limit");
|
|
217
|
-
const digest = await hashReadable(await currentReader.open(entry, signal), Math.min(limits.maxEntryBytes, remainingBytes), signal);
|
|
218
|
-
totalBytes += digest.bytes;
|
|
219
|
-
const mismatched = entry.declaredSha256 !== null && entry.declaredSha256 !== digest.sha256;
|
|
220
|
-
if (mismatched && integrity.mode === "fail")
|
|
221
|
-
throw new ArtifactReaderFailure("integrity", `Artifact integrity metadata disagrees with content: ${logicalPath}`, undefined, {
|
|
222
|
-
logicalPath,
|
|
223
|
-
declaredSha256: entry.declaredSha256,
|
|
224
|
-
calculatedSha256: digest.sha256,
|
|
225
|
-
unpacked: entry.unpacked,
|
|
226
|
-
});
|
|
227
|
-
if (mismatched && entry.declaredSha256 !== null) {
|
|
228
|
-
if (pendingContradictions.length >= integrity.maxMismatches)
|
|
229
|
-
throw new ArtifactReaderFailure("limit", "Artifact integrity mismatch limit exceeded");
|
|
230
|
-
pendingContradictions.push({
|
|
231
|
-
logicalPath,
|
|
232
|
-
declaredSha256: entry.declaredSha256,
|
|
233
|
-
observedSha256: digest.sha256,
|
|
234
|
-
entryKind: entry.kind,
|
|
235
|
-
unpacked: entry.unpacked,
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
const classified = entry.kind === "slice"
|
|
239
|
-
? { kind: "universal-slice", format: "mach-o" }
|
|
240
|
-
: classifyArtifactContent(logicalPath, digest.prefix);
|
|
241
|
-
return {
|
|
242
|
-
node: createArtifactNode({
|
|
243
|
-
sha256: digest.sha256,
|
|
244
|
-
size: digest.bytes,
|
|
245
|
-
kind: classified.kind,
|
|
246
|
-
format: classified.format,
|
|
247
|
-
executable: entry.executable,
|
|
248
|
-
contentState: "embedded",
|
|
249
|
-
limitations: mismatched
|
|
250
|
-
? [
|
|
251
|
-
"Observed content contradicts declared integrity metadata and is untrusted.",
|
|
252
|
-
]
|
|
253
|
-
: [],
|
|
254
|
-
}),
|
|
255
|
-
mismatched,
|
|
256
|
-
};
|
|
257
|
-
};
|
|
258
|
-
const visit = async (currentReader, prefix) => {
|
|
259
|
-
for await (const entry of currentReader.entries(signal)) {
|
|
260
|
-
if (occurrences.length >= limits.maxEntries)
|
|
261
|
-
throw new ArtifactReaderFailure("limit", "Artifact entry limit exceeded");
|
|
262
|
-
const logicalPath = normalizeArtifactPath(prefix.length === 0 ? entry.path : `${prefix}/${entry.path}`, limits);
|
|
263
|
-
const expandableAsar = isExpandableAsar(entry, logicalPath);
|
|
264
|
-
registry.add(logicalPath, expandableAsar ? "directory" : entry.kind);
|
|
265
|
-
preflightEntry(entry, limits);
|
|
266
|
-
const parent = nearestParent(logicalPath, occurrenceByPath);
|
|
267
|
-
const occurrence = createOccurrence(entry, logicalPath, parent?.occurrence_id ?? null);
|
|
268
|
-
const digested = await digestEntry(currentReader, entry, logicalPath);
|
|
269
|
-
if (digested !== undefined) {
|
|
270
|
-
nodes.set(digested.node.artifact_id, digested.node);
|
|
271
|
-
occurrence.artifact_id = digested.node.artifact_id;
|
|
272
|
-
occurrence.hash_status = digested.mismatched
|
|
273
|
-
? "mismatched"
|
|
274
|
-
: "verified";
|
|
275
|
-
if (digested.mismatched)
|
|
276
|
-
occurrence.limitations.push("Declared integrity metadata contradicts observed bytes.");
|
|
277
|
-
}
|
|
278
|
-
occurrences.push(occurrence);
|
|
279
|
-
occurrenceByPath.set(logicalPath, occurrence);
|
|
280
|
-
if (expandableAsar && digested?.mismatched !== true)
|
|
281
|
-
await visitNestedAsar(entry.adapterKey, logicalPath, visit);
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
await visit(reader, "");
|
|
285
|
-
return { nodes, occurrences, pendingContradictions };
|
|
286
|
-
};
|
|
287
|
-
const classifyRoot = async (path, directory) => {
|
|
288
|
-
if (directory)
|
|
289
|
-
return "directory";
|
|
290
|
-
const extensionFormat = classifyContainerExtension(path);
|
|
291
|
-
if (extensionFormat !== undefined)
|
|
292
|
-
return extensionFormat;
|
|
293
|
-
const handle = await open(path, "r");
|
|
294
|
-
try {
|
|
295
|
-
const magic = Buffer.alloc(4);
|
|
296
|
-
const observed = await handle.read(magic, 0, magic.length, 0);
|
|
297
|
-
if (observed.bytesRead === 4 &&
|
|
298
|
-
magic[0] === 0x50 &&
|
|
299
|
-
magic[1] === 0x4b &&
|
|
300
|
-
[0x03, 0x05, 0x07].includes(magic[2] ?? -1) &&
|
|
301
|
-
[0x04, 0x06, 0x08].includes(magic[3] ?? -1))
|
|
302
|
-
return "zip";
|
|
303
|
-
if (observed.bytesRead === 4) {
|
|
304
|
-
const header = magic.readUInt32BE(0);
|
|
305
|
-
if ([0xcafebabe, 0xbebafeca, 0xcafebabf, 0xbfbafeca].includes(header))
|
|
306
|
-
return "mach-o-universal";
|
|
307
|
-
if ([0xfeedface, 0xfeedfacf, 0xcefaedfe, 0xcffaedfe].includes(header))
|
|
308
|
-
return "mach-o";
|
|
309
|
-
if (magic.equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46])))
|
|
310
|
-
return "elf";
|
|
311
|
-
}
|
|
312
|
-
if (observed.bytesRead >= 2 && magic[0] === 0x4d && magic[1] === 0x5a)
|
|
313
|
-
return "pe";
|
|
314
|
-
}
|
|
315
|
-
finally {
|
|
316
|
-
await handle.close();
|
|
317
|
-
}
|
|
318
|
-
return classifyArtifactPath(path).format;
|
|
319
|
-
};
|
|
320
|
-
const classifyContainerExtension = (path) => {
|
|
321
|
-
const lower = path.toLowerCase();
|
|
322
|
-
for (const format of ["asar", "ipa", "apk", "zip", "dmg", "pkg"])
|
|
323
|
-
if (lower.endsWith(`.${format}`))
|
|
324
|
-
return format;
|
|
325
|
-
return undefined;
|
|
326
|
-
};
|
|
327
|
-
const preflightEntry = (entry, limits) => {
|
|
328
|
-
if (entry.declaredSize !== null && entry.declaredSize > limits.maxEntryBytes)
|
|
329
|
-
throw new ArtifactReaderFailure("limit", `Entry exceeds byte limit: ${entry.path}`);
|
|
330
|
-
if (entry.declaredSize !== null &&
|
|
331
|
-
entry.compressedSize !== null &&
|
|
332
|
-
entry.compressedSize === 0 &&
|
|
333
|
-
entry.declaredSize > 0)
|
|
334
|
-
throw new ArtifactReaderFailure("limit", `Invalid compression ratio: ${entry.path}`);
|
|
335
|
-
if (entry.declaredSize !== null &&
|
|
336
|
-
entry.compressedSize !== null &&
|
|
337
|
-
entry.compressedSize > 0 &&
|
|
338
|
-
entry.declaredSize / entry.compressedSize > limits.maxCompressionRatio)
|
|
339
|
-
throw new ArtifactReaderFailure("limit", `Compression ratio exceeds limit: ${entry.path}`);
|
|
340
|
-
};
|
|
341
|
-
const hashReadable = async (stream, maximum, signal) => {
|
|
342
|
-
const hash = createHash("sha256");
|
|
343
|
-
const prefixes = [];
|
|
344
|
-
let prefixBytes = 0;
|
|
345
|
-
let bytes = 0;
|
|
346
|
-
for await (const raw of stream) {
|
|
347
|
-
abortIfNeeded(signal);
|
|
348
|
-
const chunk = streamChunkToBuffer(raw);
|
|
349
|
-
bytes += chunk.length;
|
|
350
|
-
if (bytes > maximum) {
|
|
351
|
-
stream.destroy();
|
|
352
|
-
throw new ArtifactReaderFailure("limit", "Observed entry bytes exceed limit");
|
|
353
|
-
}
|
|
354
|
-
hash.update(chunk);
|
|
355
|
-
if (prefixBytes < 16) {
|
|
356
|
-
const selected = chunk.subarray(0, 16 - prefixBytes);
|
|
357
|
-
prefixes.push(selected);
|
|
358
|
-
prefixBytes += selected.length;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return { sha256: hash.digest("hex"), bytes, prefix: Buffer.concat(prefixes) };
|
|
362
|
-
};
|
|
363
|
-
const abortIfNeeded = (signal) => {
|
|
364
|
-
if (signal?.aborted === true)
|
|
365
|
-
throw new ArtifactReaderFailure("cancelled", "Artifact inventory cancelled");
|
|
366
|
-
};
|
|
@@ -4,7 +4,7 @@ import { withinRoot } from "../reference/ReferenceSourceReaderPaths.js";
|
|
|
4
4
|
import { scanCanonicalArtifactInventory, } from "./ArtifactInventory.js";
|
|
5
5
|
import { canonicalizeConfiguredRoots } from "./ConfiguredRoots.js";
|
|
6
6
|
/** Resolve, authorize, and scan one artifact without a second path resolution. */
|
|
7
|
-
export const scanAuthorizedArtifactInventory = async (inputPath, roots, limits,
|
|
7
|
+
export const scanAuthorizedArtifactInventory = async (inputPath, roots, limits, options = {}) => {
|
|
8
8
|
if (roots.length === 0)
|
|
9
9
|
throw new ArtifactReaderFailure("path", "Artifact input roots are disabled");
|
|
10
10
|
const [path, approved] = await Promise.all([
|
|
@@ -13,5 +13,5 @@ export const scanAuthorizedArtifactInventory = async (inputPath, roots, limits,
|
|
|
13
13
|
]);
|
|
14
14
|
if (!approved.some((root) => withinRoot(root, path)))
|
|
15
15
|
throw new ArtifactReaderFailure("path", "Artifact path is outside approved input roots");
|
|
16
|
-
return scanCanonicalArtifactInventory(path, limits,
|
|
16
|
+
return scanCanonicalArtifactInventory(path, limits, options);
|
|
17
17
|
};
|