rea-agents 2.5.0 → 3.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 +20 -12
- package/bridge/ghidra/ReaGhidraBridge.java +477 -4
- package/bridge/hopper_bridge.py +54 -4
- package/dist/application/AnalysisContextQueries.js +142 -0
- package/dist/application/AnalysisSnapshotCache.js +4 -2
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
- package/dist/application/ArtifactInventory/scanReader.js +7 -7
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/BinarySession.js +19 -20
- package/dist/application/BinarySessionComposition.js +21 -0
- package/dist/application/BinarySessionRecords.js +106 -10
- package/dist/application/BinarySessionStatus.js +11 -5
- package/dist/application/BrowserEvidence.js +3 -5
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +140 -55
- package/dist/application/ClientRegistrationStatus.js +4 -1
- package/dist/application/CrossVersionInventory.js +7 -6
- package/dist/application/DirectAnalysis.js +6 -2
- package/dist/application/ElectronActiveEvidence.js +55 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +81 -0
- package/dist/application/EnhancedTools.js +49 -17
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +53 -17
- package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/LazyAnalysisProvider.js +77 -0
- package/dist/application/LoopbackReplay.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- package/dist/application/NativeApiInspection.js +80 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
- package/dist/application/ProcessCaptureLifecycle.js +5 -0
- package/dist/application/ProcessCli.js +2 -1
- package/dist/application/ProcessHarness.js +8 -3
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReferenceSourceImport.js +2 -2
- package/dist/application/SessionProviderRouter.js +6 -6
- package/dist/application/SetupClientConfiguration.js +10 -3
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/application/runtime.js +26 -9
- package/dist/artifacts/ArtifactProvider.js +8 -10
- package/dist/artifacts/SafeOutputTree.js +7 -8
- package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
- package/dist/browser/CdpElectronInspection.js +3 -1
- package/dist/browser/JavaScriptRuntimeScope.js +5 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
- package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
- package/dist/browser/PlaywrightScenarioSession.js +4 -4
- package/dist/browser/SensitiveTextCapture.js +1 -1
- package/dist/browser/V8InspectorCaptureProjection.js +1 -0
- package/dist/browser/V8InspectorProvider.js +3 -3
- package/dist/catalogIdentity.js +15 -9
- package/dist/cli/artifactCommands.js +5 -3
- package/dist/cli/coreAnalysisCommands.js +41 -0
- package/dist/cli/managedCommands.js +1 -1
- package/dist/cliApplicationCommands.js +2 -2
- package/dist/cliBrowserAdvancedCommands.js +11 -5
- package/dist/cliBrowserCommands.js +14 -7
- package/dist/cliCommandNames.js +2 -0
- package/dist/cliElectronCommands.js +46 -4
- package/dist/cliJavaScriptRuntimeCommands.js +14 -6
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -0
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -200
- package/dist/config/parsers.js +10 -1
- package/dist/config/passiveObservation.js +157 -0
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/applicationToolContracts.js +2 -5
- package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
- package/dist/contracts/artifactToolContracts.js +35 -37
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +21 -27
- package/dist/contracts/functionWorkflowToolContracts.js +29 -0
- package/dist/contracts/managedToolContracts.js +4 -9
- package/dist/contracts/managedWorkflowExamples.js +12 -9
- package/dist/contracts/managedWorkflowToolContracts.js +30 -27
- package/dist/contracts/nativeToolContracts.js +2 -3
- package/dist/contracts/promptContracts.js +14 -15
- package/dist/contracts/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +4 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +12 -67
- package/dist/contracts/toolEffects.js +19 -0
- package/dist/contracts/toolOutputSchemaGroups.js +66 -11
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +8 -2
- package/dist/domain/analysisErrorProjection.js +1 -0
- package/dist/domain/androidApplication.js +2 -0
- package/dist/domain/appleApplication.js +2 -0
- package/dist/domain/binaryTarget.js +7 -5
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +21 -69
- package/dist/domain/browserObservation.js +22 -9
- package/dist/domain/bytecodeProvider.js +177 -0
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformancePackage.js +169 -0
- package/dist/domain/conformanceReplay.js +104 -0
- package/dist/domain/conformanceTrustGate.js +328 -0
- package/dist/domain/customProtocolCapture.js +137 -0
- package/dist/domain/electronActiveObservation.js +277 -0
- package/dist/domain/electronObservation.js +15 -11
- package/dist/domain/electronStaticAnalysisValues.js +4 -1
- package/dist/domain/eventProcessTree.js +217 -0
- package/dist/domain/evidenceBundle.js +47 -0
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +68 -68
- package/dist/domain/inputIssueProjection.js +11 -2
- package/dist/domain/investigationWorkspace.js +16 -15
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
- package/dist/domain/javascriptReplay.js +79 -63
- package/dist/domain/javascriptRuntimeObservation.js +1 -0
- package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
- package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +8 -12
- package/dist/domain/javascriptSourceParser.js +15 -0
- package/dist/domain/javascriptStaticAnalysis.js +8 -12
- package/dist/domain/knownPageCoverage.js +15 -7
- package/dist/domain/mobileApplicationInvestigation.js +159 -0
- package/dist/domain/nativeApiBoundary.js +138 -0
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- package/dist/domain/objcSwiftMetadata.js +150 -0
- package/dist/domain/packageAnalysis.js +123 -0
- package/dist/domain/peInspection.js +196 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +7 -3
- package/dist/domain/processComparison.js +12 -7
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +14 -7
- package/dist/domain/processReactiveTransition.js +9 -3
- package/dist/domain/processScenario.js +6 -3
- package/dist/domain/processTraceComparison.js +3 -2
- package/dist/domain/protocolCapture.js +245 -0
- package/dist/domain/reconstructionReadinessSchemas.js +30 -2
- package/dist/domain/referenceSourceImportParsing.js +2 -2
- package/dist/domain/replayMachineRuntime.js +5 -3
- package/dist/domain/sourceToBundleComparison.js +2 -2
- package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
- package/dist/domain/sourceToBundleSignals.js +7 -1
- package/dist/domain/staticRuntimeCorrelation.js +7 -5
- package/dist/domain/webBundleAnalysis.js +14 -14
- package/dist/domain/webCaptureDiff.js +15 -12
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
- package/dist/dotnet/ManagedStaticProvider.js +34 -5
- package/dist/generatedMcpToolCatalog.js +37 -0
- package/dist/generatedPackageMetadata.js +4 -4
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +44 -16
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +3 -1
- package/dist/hopper/HopperAnalysisProfile.js +2 -4
- package/dist/hopper/HopperCleanup.js +5 -6
- package/dist/hopper/HopperClient.js +27 -3
- package/dist/hopper/HopperProvider.js +42 -44
- package/dist/hopper/HopperRequestQueue.js +32 -4
- package/dist/hopper/HopperResponseStream.js +2 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/hopper/protocol.js +63 -21
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +31 -41
- package/dist/main.js +17 -13
- package/dist/mcpDoctor.js +4 -26
- package/dist/mcpStartupPolicy.js +14 -0
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +64 -128
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +88 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +3 -3
- package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
- package/dist/replay/JavaScriptReplayWorker.js +95 -11
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
- package/dist/replay/ReplayOutcome.js +26 -15
- package/dist/replay/ReplayWorkerProtocol.js +34 -29
- package/dist/server/createServer.js +101 -144
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/registerApplicationTools/characterization.js +6 -13
- package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
- package/dist/server/registerApplicationTools/compareVersions.js +3 -8
- package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
- package/dist/server/registerApplicationTools/coverage.js +13 -19
- package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
- package/dist/server/registerApplicationTools/readiness.js +1 -6
- package/dist/server/registerApplicationTools/traceFeature.js +3 -8
- package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
- package/dist/server/registerArtifactComparisonTool.js +12 -16
- package/dist/server/registerBrowserScenarioTool.js +1 -6
- package/dist/server/registerBrowserTools.js +37 -79
- package/dist/server/registerBundleComparisonTool.js +10 -14
- package/dist/server/registerCloseLifecycleTool.js +6 -14
- package/dist/server/registerElectronTools.js +30 -47
- package/dist/server/registerEnhancedTools.js +124 -122
- package/dist/server/registerEvidenceResources.js +50 -101
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +42 -59
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
- package/dist/server/registerOfficialTools.js +8 -9
- package/dist/server/registerProcessComparisonTool.js +19 -24
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
- package/dist/server/registerReconstructionReadinessResource.js +0 -7
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +146 -47
- package/dist/server/registerSessionStatusTool.js +14 -29
- package/dist/server/registerSessionTools.js +45 -41
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -177
- package/dist/server/toolResult.js +14 -18
- package/package.json +35 -16
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/skills/reverse-engineer-anything/SKILL.md +10 -3
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/toolInputValidation.js +0 -77
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import { controlledReplayExecutionOutputSchema, controlledReplayPlanInputSchema, controlledReplayPlanOutputSchema, } from "./javascriptReplay.js";
|
|
3
3
|
import { javascriptExportInstrumentationInputSchema, javascriptExportTransformationManifestSchema, } from "./javascriptExportInstrumentation.js";
|
|
4
4
|
import { runtimeCharacterizationPlanSchema } from "./runtimeCharacterization.js";
|
|
5
5
|
import { evidenceRecordSchema } from "./evidence.js";
|
|
6
6
|
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
7
|
+
const nodeCharacterizationExpectedEffectSchema = z.enum([
|
|
8
|
+
"pure",
|
|
9
|
+
"observation-only",
|
|
10
|
+
]);
|
|
11
|
+
const nodeRuntimeCharacterizationPlanSchema = runtimeCharacterizationPlanSchema.extend({
|
|
12
|
+
expected_effect: nodeCharacterizationExpectedEffectSchema,
|
|
13
|
+
});
|
|
7
14
|
export const nodeCharacterizationPreparationInputSchema = z
|
|
8
15
|
.strictObject({
|
|
9
16
|
preparation_approved: z.literal(true),
|
|
10
17
|
selected_alias: z.string().min(1).max(200),
|
|
11
|
-
expected_effect:
|
|
18
|
+
expected_effect: nodeCharacterizationExpectedEffectSchema,
|
|
12
19
|
instrumentation: javascriptExportInstrumentationInputSchema,
|
|
13
|
-
replay:
|
|
20
|
+
replay: controlledReplayPlanInputSchema,
|
|
14
21
|
})
|
|
15
22
|
.superRefine((input, context) => {
|
|
16
|
-
if (input.replay.mode !== "plan")
|
|
17
|
-
context.addIssue({
|
|
18
|
-
code: "custom",
|
|
19
|
-
path: ["replay", "mode"],
|
|
20
|
-
message: "Characterization preparation requires replay plan mode",
|
|
21
|
-
});
|
|
22
23
|
const selected = input.replay.left.modules.filter(({ alias }) => alias === input.selected_alias);
|
|
23
24
|
if (selected.length !== 1 ||
|
|
24
25
|
selected[0]?.path !== input.instrumentation.artifact_path ||
|
|
@@ -50,17 +51,17 @@ export const nodeCharacterizationExecutionInputSchema = z.strictObject({
|
|
|
50
51
|
export const nodeCharacterizationPreparationOutputSchema = z.strictObject({
|
|
51
52
|
schema_version: z.literal(1),
|
|
52
53
|
phase: z.literal("preparation"),
|
|
53
|
-
plan:
|
|
54
|
+
plan: nodeRuntimeCharacterizationPlanSchema,
|
|
54
55
|
transformation: javascriptExportTransformationManifestSchema,
|
|
55
56
|
transformation_evidence: evidenceRecordSchema,
|
|
56
|
-
replay:
|
|
57
|
+
replay: controlledReplayPlanOutputSchema,
|
|
57
58
|
});
|
|
58
59
|
export const nodeCharacterizationExecutionOutputSchema = z.strictObject({
|
|
59
60
|
schema_version: z.literal(1),
|
|
60
61
|
phase: z.literal("execution"),
|
|
61
|
-
plan:
|
|
62
|
+
plan: nodeRuntimeCharacterizationPlanSchema,
|
|
62
63
|
transformation: javascriptExportTransformationManifestSchema,
|
|
63
64
|
transformation_evidence: evidenceRecordSchema,
|
|
64
65
|
evidence: evidenceRecordSchema,
|
|
65
|
-
replay:
|
|
66
|
+
replay: controlledReplayExecutionOutputSchema,
|
|
66
67
|
});
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Objective-C method type. */
|
|
3
|
+
export const objcMethodTypeSchema = z.enum([
|
|
4
|
+
"instance",
|
|
5
|
+
"class",
|
|
6
|
+
"ivar_getter",
|
|
7
|
+
"ivar_setter",
|
|
8
|
+
]);
|
|
9
|
+
/** Objective-C property attribute. */
|
|
10
|
+
export const objcPropertyAttributeSchema = z.strictObject({
|
|
11
|
+
name: z.string().min(1),
|
|
12
|
+
value: z.string(),
|
|
13
|
+
is_weak: z.boolean().default(false),
|
|
14
|
+
is_atomic: z.boolean().default(false),
|
|
15
|
+
is_copy: z.boolean().default(false),
|
|
16
|
+
is_strong: z.boolean().default(false),
|
|
17
|
+
});
|
|
18
|
+
/** Objective-C method metadata. */
|
|
19
|
+
export const objcMethodSchema = z.strictObject({
|
|
20
|
+
selector: z.string().min(1),
|
|
21
|
+
method_type: objcMethodTypeSchema,
|
|
22
|
+
address: z.number().int().nullable(),
|
|
23
|
+
is_required: z.boolean().default(false),
|
|
24
|
+
is_optional: z.boolean().default(false),
|
|
25
|
+
});
|
|
26
|
+
/** Objective-C property metadata. */
|
|
27
|
+
export const objcPropertySchema = z.strictObject({
|
|
28
|
+
name: z.string().min(1),
|
|
29
|
+
type_encoding: z.string().nullable(),
|
|
30
|
+
attributes: z.array(objcPropertyAttributeSchema).default([]),
|
|
31
|
+
is_readonly: z.boolean().default(false),
|
|
32
|
+
getter: z.string().nullable(),
|
|
33
|
+
setter: z.string().nullable(),
|
|
34
|
+
});
|
|
35
|
+
/** Objective-C protocol metadata. */
|
|
36
|
+
export const objcProtocolSchema = z.strictObject({
|
|
37
|
+
name: z.string().min(1),
|
|
38
|
+
methods: z.array(objcMethodSchema).default([]),
|
|
39
|
+
optional_methods: z.array(objcMethodSchema).default([]),
|
|
40
|
+
properties: z.array(objcPropertySchema).default([]),
|
|
41
|
+
});
|
|
42
|
+
/** Objective-C class metadata. */
|
|
43
|
+
export const objcClassSchema = z.strictObject({
|
|
44
|
+
name: z.string().min(1),
|
|
45
|
+
super_class: z.string().nullable(),
|
|
46
|
+
is_meta_class: z.boolean().default(false),
|
|
47
|
+
is_root_class: z.boolean().default(false),
|
|
48
|
+
methods: z.array(objcMethodSchema).default([]),
|
|
49
|
+
properties: z.array(objcPropertySchema).default([]),
|
|
50
|
+
protocols: z.array(z.string()).default([]),
|
|
51
|
+
ivar_count: z.number().int().nonnegative().default(0),
|
|
52
|
+
instance_size: z.number().int().nonnegative().nullable(),
|
|
53
|
+
});
|
|
54
|
+
/** Swift declaration kind. */
|
|
55
|
+
export const swiftDeclKindSchema = z.enum([
|
|
56
|
+
"class",
|
|
57
|
+
"struct",
|
|
58
|
+
"enum",
|
|
59
|
+
"protocol",
|
|
60
|
+
"extension",
|
|
61
|
+
"actor",
|
|
62
|
+
"global_var",
|
|
63
|
+
"global_func",
|
|
64
|
+
]);
|
|
65
|
+
/** Swift access level. */
|
|
66
|
+
export const swiftAccessLevelSchema = z.enum([
|
|
67
|
+
"private",
|
|
68
|
+
"fileprivate",
|
|
69
|
+
"internal",
|
|
70
|
+
"public",
|
|
71
|
+
"open",
|
|
72
|
+
]);
|
|
73
|
+
/** Swift declaration metadata. */
|
|
74
|
+
export const swiftDeclSchema = z.strictObject({
|
|
75
|
+
kind: swiftDeclKindSchema,
|
|
76
|
+
name: z.string().min(1),
|
|
77
|
+
module: z.string().nullable(),
|
|
78
|
+
access_level: swiftAccessLevelSchema.default("internal"),
|
|
79
|
+
super_class: z.string().nullable(),
|
|
80
|
+
protocols: z.array(z.string()).default([]),
|
|
81
|
+
is_final: z.boolean().default(false),
|
|
82
|
+
is_required: z.boolean().default(false),
|
|
83
|
+
is_convenience_init: z.boolean().default(false),
|
|
84
|
+
is_override: z.boolean().default(false),
|
|
85
|
+
});
|
|
86
|
+
/** Database save/read operation type. */
|
|
87
|
+
export const dbOperationSchema = z.enum([
|
|
88
|
+
"save",
|
|
89
|
+
"readback",
|
|
90
|
+
"open_database",
|
|
91
|
+
"close_database",
|
|
92
|
+
"export",
|
|
93
|
+
"import",
|
|
94
|
+
]);
|
|
95
|
+
/** Database save operation result. */
|
|
96
|
+
export const dbSaveResultSchema = z.strictObject({
|
|
97
|
+
operation: dbOperationSchema,
|
|
98
|
+
succeeded: z.boolean(),
|
|
99
|
+
preserved_names: z.number().int().nonnegative().default(0),
|
|
100
|
+
preserved_comments: z.number().int().nonnegative().default(0),
|
|
101
|
+
preserved_bookmarks: z.number().int().nonnegative().default(0),
|
|
102
|
+
database_path: z.string().nullable(),
|
|
103
|
+
error: z.string().nullable(),
|
|
104
|
+
});
|
|
105
|
+
/** Result of deeper ObjC/Swift metadata extraction. */
|
|
106
|
+
export const objcSwiftMetadataSchema = z.strictObject({
|
|
107
|
+
objc_classes: z.array(objcClassSchema).default([]),
|
|
108
|
+
objc_protocols: z.array(objcProtocolSchema).default([]),
|
|
109
|
+
swift_decls: z.array(swiftDeclSchema).default([]),
|
|
110
|
+
db_save_result: dbSaveResultSchema.nullable(),
|
|
111
|
+
});
|
|
112
|
+
/** Check if a selector name looks like a getter. */
|
|
113
|
+
export function isGetterSelector(selector) {
|
|
114
|
+
return /^[a-z][a-zA-Z0-9_]*$/u.test(selector) && !selector.includes(":");
|
|
115
|
+
}
|
|
116
|
+
/** Check if a selector name looks like a setter. */
|
|
117
|
+
export function isSetterSelector(selector) {
|
|
118
|
+
return selector.startsWith("set") && selector.endsWith(":");
|
|
119
|
+
}
|
|
120
|
+
/** Extract property name from a getter/setter selector. */
|
|
121
|
+
export function propertyNameFromSelector(selector) {
|
|
122
|
+
if (isSetterSelector(selector)) {
|
|
123
|
+
const inner = selector.slice(3, -1);
|
|
124
|
+
return inner.charAt(0).toLowerCase() + inner.slice(1);
|
|
125
|
+
}
|
|
126
|
+
if (isGetterSelector(selector)) {
|
|
127
|
+
return selector;
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
/** Count ObjC methods by type. */
|
|
132
|
+
export function countMethodsByType(methods) {
|
|
133
|
+
return {
|
|
134
|
+
instance: methods.filter((m) => m.method_type === "instance").length,
|
|
135
|
+
class: methods.filter((m) => m.method_type === "class").length,
|
|
136
|
+
ivar_getter: methods.filter((m) => m.method_type === "ivar_getter").length,
|
|
137
|
+
ivar_setter: methods.filter((m) => m.method_type === "ivar_setter").length,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
/** Get all Swift declarations of a specific kind. */
|
|
141
|
+
export function swiftDeclsByKind(decls, kind) {
|
|
142
|
+
return decls.filter((d) => d.kind === kind);
|
|
143
|
+
}
|
|
144
|
+
/** Check if a database save preserved all expected items. */
|
|
145
|
+
export function isDbSaveComplete(result, expectedNames, expectedComments, expectedBookmarks) {
|
|
146
|
+
return (result.succeeded &&
|
|
147
|
+
result.preserved_names >= expectedNames &&
|
|
148
|
+
result.preserved_comments >= expectedComments &&
|
|
149
|
+
result.preserved_bookmarks >= expectedBookmarks);
|
|
150
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Supported Windows package formats. */
|
|
3
|
+
export const packageFormatSchema = z.enum(["msix", "msi", "appx"]);
|
|
4
|
+
/** A resource entry within a package. */
|
|
5
|
+
export const packageResourceSchema = z.strictObject({
|
|
6
|
+
/** Resource path within the package. */
|
|
7
|
+
path: z.string().min(1),
|
|
8
|
+
/** Resource type. */
|
|
9
|
+
type: z.enum([
|
|
10
|
+
"manifest",
|
|
11
|
+
"icon",
|
|
12
|
+
"configuration",
|
|
13
|
+
"certificate",
|
|
14
|
+
"executable",
|
|
15
|
+
"library",
|
|
16
|
+
"data",
|
|
17
|
+
"other",
|
|
18
|
+
]),
|
|
19
|
+
/** Size in bytes. */
|
|
20
|
+
size: z.number().int().nonnegative(),
|
|
21
|
+
/** SHA-256 digest. */
|
|
22
|
+
digest: z
|
|
23
|
+
.string()
|
|
24
|
+
.regex(/^[a-f0-9]{64}$/u)
|
|
25
|
+
.nullable(),
|
|
26
|
+
});
|
|
27
|
+
/** Digital signature information. */
|
|
28
|
+
export const digitalSignatureSchema = z.strictObject({
|
|
29
|
+
/** Whether the package is signed. */
|
|
30
|
+
is_signed: z.boolean(),
|
|
31
|
+
/** Signer subject name. */
|
|
32
|
+
signer_subject: z.string().nullable(),
|
|
33
|
+
/** Certificate thumbprint. */
|
|
34
|
+
certificate_thumbprint: z.string().nullable(),
|
|
35
|
+
/** Whether the signature is valid. */
|
|
36
|
+
is_valid: z.boolean().default(false),
|
|
37
|
+
/** Whether the signature is timestamped. */
|
|
38
|
+
is_timestamped: z.boolean().default(false),
|
|
39
|
+
/** Timestamp signer if present. */
|
|
40
|
+
timestamp_signer: z.string().nullable(),
|
|
41
|
+
});
|
|
42
|
+
/** A Windows package manifest for static analysis. */
|
|
43
|
+
export const packageManifestSchema = z.strictObject({
|
|
44
|
+
/** Package format. */
|
|
45
|
+
format: packageFormatSchema,
|
|
46
|
+
/** Package identity name. */
|
|
47
|
+
name: z.string().min(1),
|
|
48
|
+
/** Package publisher. */
|
|
49
|
+
publisher: z.string().nullable(),
|
|
50
|
+
/** Package version. */
|
|
51
|
+
version: z.string().nullable(),
|
|
52
|
+
/** Architecture. */
|
|
53
|
+
architecture: z.enum(["x86", "x64", "arm", "arm64", "neutral", "unknown"]),
|
|
54
|
+
/** Package resources. */
|
|
55
|
+
resources: z.array(packageResourceSchema).default([]),
|
|
56
|
+
/** Digital signature. */
|
|
57
|
+
signature: digitalSignatureSchema,
|
|
58
|
+
/** Whether the package is a framework. */
|
|
59
|
+
is_framework: z.boolean().default(false),
|
|
60
|
+
/** Package dependencies. */
|
|
61
|
+
dependencies: z.array(z.string()).default([]),
|
|
62
|
+
/** Capabilities declared in the manifest. */
|
|
63
|
+
capabilities: z.array(z.string()).default([]),
|
|
64
|
+
});
|
|
65
|
+
/** Detect package format from file extension. */
|
|
66
|
+
export function detectPackageFormat(path) {
|
|
67
|
+
const lower = path.toLowerCase();
|
|
68
|
+
if (lower.endsWith(".msix"))
|
|
69
|
+
return "msix";
|
|
70
|
+
if (lower.endsWith(".msi"))
|
|
71
|
+
return "msi";
|
|
72
|
+
if (lower.endsWith(".appx"))
|
|
73
|
+
return "appx";
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/** Check if a resource path looks like a manifest. */
|
|
77
|
+
export function isManifestResource(path) {
|
|
78
|
+
const lower = path.toLowerCase();
|
|
79
|
+
return (lower.includes("appxmanifest.xml") ||
|
|
80
|
+
lower.includes("appxmanifest") ||
|
|
81
|
+
lower.includes("manifest.xml") ||
|
|
82
|
+
lower.endsWith("_manifest.xml"));
|
|
83
|
+
}
|
|
84
|
+
/** Check if a resource path looks like a configuration file. */
|
|
85
|
+
export function isConfigurationResource(path) {
|
|
86
|
+
const lower = path.toLowerCase();
|
|
87
|
+
return (lower.endsWith(".xml") ||
|
|
88
|
+
lower.endsWith(".json") ||
|
|
89
|
+
lower.endsWith(".ini") ||
|
|
90
|
+
lower.endsWith(".config"));
|
|
91
|
+
}
|
|
92
|
+
/** Classify a resource by its path. */
|
|
93
|
+
export function classifyResource(path) {
|
|
94
|
+
if (isManifestResource(path))
|
|
95
|
+
return "manifest";
|
|
96
|
+
const lower = path.toLowerCase();
|
|
97
|
+
if (lower.endsWith(".ico") ||
|
|
98
|
+
lower.endsWith(".png") ||
|
|
99
|
+
lower.endsWith(".jpg") ||
|
|
100
|
+
lower.endsWith(".jpeg"))
|
|
101
|
+
return "icon";
|
|
102
|
+
if (isConfigurationResource(path))
|
|
103
|
+
return "configuration";
|
|
104
|
+
if (lower.endsWith(".cer") ||
|
|
105
|
+
lower.endsWith(".pfx") ||
|
|
106
|
+
lower.endsWith(".p12"))
|
|
107
|
+
return "certificate";
|
|
108
|
+
if (lower.endsWith(".exe") || lower.endsWith(".dll"))
|
|
109
|
+
return lower.endsWith(".exe") ? "executable" : "library";
|
|
110
|
+
return "other";
|
|
111
|
+
}
|
|
112
|
+
/** Get all resources of a specific type. */
|
|
113
|
+
export function resourcesByType(manifest, type) {
|
|
114
|
+
return manifest.resources.filter((r) => r.type === type);
|
|
115
|
+
}
|
|
116
|
+
/** Get the total size of all resources. */
|
|
117
|
+
export function totalResourceSize(manifest) {
|
|
118
|
+
return manifest.resources.reduce((sum, r) => sum + r.size, 0);
|
|
119
|
+
}
|
|
120
|
+
/** Check if a package has a valid signature. */
|
|
121
|
+
export function hasValidSignature(manifest) {
|
|
122
|
+
return manifest.signature.is_signed && manifest.signature.is_valid;
|
|
123
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** PE/COFF section characteristics flags. */
|
|
3
|
+
export const sectionCharacteristicsSchema = z.object({
|
|
4
|
+
/** Section contains executable code. */
|
|
5
|
+
has_code: z.boolean().default(false),
|
|
6
|
+
/** Section contains initialized data. */
|
|
7
|
+
has_initialized_data: z.boolean().default(false),
|
|
8
|
+
/** Section contains uninitialized data. */
|
|
9
|
+
has_uninitialized_data: z.boolean().default(false),
|
|
10
|
+
/** Section can be read. */
|
|
11
|
+
readable: z.boolean().default(false),
|
|
12
|
+
/** Section can be written. */
|
|
13
|
+
writable: z.boolean().default(false),
|
|
14
|
+
/** Section can be executed. */
|
|
15
|
+
executable: z.boolean().default(false),
|
|
16
|
+
});
|
|
17
|
+
/** PE/COFF section header. */
|
|
18
|
+
export const peSectionSchema = z.strictObject({
|
|
19
|
+
name: z.string().min(1),
|
|
20
|
+
virtual_size: z.number().int().nonnegative(),
|
|
21
|
+
virtual_address: z.number().int().nonnegative(),
|
|
22
|
+
raw_size: z.number().int().nonnegative(),
|
|
23
|
+
raw_offset: z.number().int().nonnegative(),
|
|
24
|
+
characteristics: sectionCharacteristicsSchema,
|
|
25
|
+
});
|
|
26
|
+
/** PE import entry. */
|
|
27
|
+
export const peImportSchema = z.strictObject({
|
|
28
|
+
dll: z.string().min(1),
|
|
29
|
+
function_name: z.string().min(1),
|
|
30
|
+
ordinal: z.number().int().nullable(),
|
|
31
|
+
is_delay_import: z.boolean().default(false),
|
|
32
|
+
});
|
|
33
|
+
/** PE export entry. */
|
|
34
|
+
export const peExportSchema = z.strictObject({
|
|
35
|
+
name: z.string().min(1),
|
|
36
|
+
ordinal: z.number().int().nonnegative(),
|
|
37
|
+
rva: z.number().int().nonnegative(),
|
|
38
|
+
forwarder: z.string().nullable(),
|
|
39
|
+
});
|
|
40
|
+
/** PE/COFF resource entry. */
|
|
41
|
+
export const peResourceSchema = z.strictObject({
|
|
42
|
+
type: z.string().min(1),
|
|
43
|
+
name: z.string().nullable(),
|
|
44
|
+
language: z.number().int().nullable(),
|
|
45
|
+
rva: z.number().int().nonnegative(),
|
|
46
|
+
size: z.number().int().nonnegative(),
|
|
47
|
+
});
|
|
48
|
+
/** PE debug directory entry. */
|
|
49
|
+
export const peDebugEntrySchema = z.strictObject({
|
|
50
|
+
type: z.string().min(1),
|
|
51
|
+
rva: z.number().int().nonnegative(),
|
|
52
|
+
size: z.number().int().nonnegative(),
|
|
53
|
+
/** PDB GUID if this is a CodeView entry. */
|
|
54
|
+
pdb_guid: z.string().nullable(),
|
|
55
|
+
/** PDB age if this is a CodeView entry. */
|
|
56
|
+
pdb_age: z.number().int().nullable(),
|
|
57
|
+
/** PDB path if this is a CodeView entry. */
|
|
58
|
+
pdb_path: z.string().nullable(),
|
|
59
|
+
});
|
|
60
|
+
/** TLS callback entry. */
|
|
61
|
+
export const peTlsCallbackSchema = z.strictObject({
|
|
62
|
+
callback_rva: z.number().int().nonnegative(),
|
|
63
|
+
index: z.number().int().nonnegative(),
|
|
64
|
+
});
|
|
65
|
+
/** Architecture/machine type. */
|
|
66
|
+
export const peMachineTypeSchema = z.enum([
|
|
67
|
+
"x86",
|
|
68
|
+
"x64",
|
|
69
|
+
"arm",
|
|
70
|
+
"arm64",
|
|
71
|
+
"ia64",
|
|
72
|
+
"unknown",
|
|
73
|
+
]);
|
|
74
|
+
/** PE/COFF manifest for static inspection. */
|
|
75
|
+
export const peManifestSchema = z.strictObject({
|
|
76
|
+
/** DOS header magic. */
|
|
77
|
+
dos_magic: z.literal(0x5a4d),
|
|
78
|
+
/** PE signature. */
|
|
79
|
+
pe_signature: z.literal(0x00004550),
|
|
80
|
+
/** Machine type. */
|
|
81
|
+
machine: peMachineTypeSchema,
|
|
82
|
+
/** Number of sections. */
|
|
83
|
+
number_of_sections: z.number().int().positive(),
|
|
84
|
+
/** Timestamp from the COFF header. */
|
|
85
|
+
timestamp: z.number().int().nullable(),
|
|
86
|
+
/** PE characteristics flags. */
|
|
87
|
+
is_dll: z.boolean().default(false),
|
|
88
|
+
is_executable: z.boolean().default(false),
|
|
89
|
+
is_console: z.boolean().default(true),
|
|
90
|
+
/** Entry point RVA. */
|
|
91
|
+
entry_point: z.number().int().nonnegative(),
|
|
92
|
+
/** Image base. */
|
|
93
|
+
image_base: z.number().int().nonnegative(),
|
|
94
|
+
/** Section alignment. */
|
|
95
|
+
section_alignment: z.number().int().positive(),
|
|
96
|
+
/** Subsystem version. */
|
|
97
|
+
subsystem_version: z.string().nullable(),
|
|
98
|
+
/** Sections. */
|
|
99
|
+
sections: z.array(peSectionSchema).min(0).max(96),
|
|
100
|
+
/** Imports. */
|
|
101
|
+
imports: z.array(peImportSchema).default([]),
|
|
102
|
+
/** Exports. */
|
|
103
|
+
exports: z.array(peExportSchema).default([]),
|
|
104
|
+
/** Resources. */
|
|
105
|
+
resources: z.array(peResourceSchema).default([]),
|
|
106
|
+
/** Debug directory entries. */
|
|
107
|
+
debug_entries: z.array(peDebugEntrySchema).default([]),
|
|
108
|
+
/** TLS callbacks. */
|
|
109
|
+
tls_callbacks: z.array(peTlsCallbackSchema).default([]),
|
|
110
|
+
/** Relocations count (not all entries). */
|
|
111
|
+
relocations_count: z.number().int().nonnegative().default(0),
|
|
112
|
+
/** Image file characteristics. */
|
|
113
|
+
image_characteristics: z.array(z.string()).default([]),
|
|
114
|
+
});
|
|
115
|
+
/** Parse machine type from COFF machine field. */
|
|
116
|
+
export function parseMachineType(machine) {
|
|
117
|
+
switch (machine) {
|
|
118
|
+
case 0x014c:
|
|
119
|
+
return "x86";
|
|
120
|
+
case 0x8664:
|
|
121
|
+
return "x64";
|
|
122
|
+
case 0x01c0:
|
|
123
|
+
case 0x01c4:
|
|
124
|
+
return "arm";
|
|
125
|
+
case 0xaa64:
|
|
126
|
+
return "arm64";
|
|
127
|
+
case 0x0200:
|
|
128
|
+
return "ia64";
|
|
129
|
+
default:
|
|
130
|
+
return "unknown";
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Parse section characteristics flags. */
|
|
134
|
+
export function parseSectionCharacteristics(characteristics) {
|
|
135
|
+
const IMAGE_SCN_CNT_CODE = 0x00000020;
|
|
136
|
+
const IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040;
|
|
137
|
+
const IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080;
|
|
138
|
+
const IMAGE_SCN_MEM_READ = 0x40000000;
|
|
139
|
+
const IMAGE_SCN_MEM_WRITE = 0x80000000;
|
|
140
|
+
const IMAGE_SCN_MEM_EXECUTE = 0x20000000;
|
|
141
|
+
return {
|
|
142
|
+
has_code: (characteristics & IMAGE_SCN_CNT_CODE) !== 0,
|
|
143
|
+
has_initialized_data: (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) !== 0,
|
|
144
|
+
has_uninitialized_data: (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) !== 0,
|
|
145
|
+
readable: (characteristics & IMAGE_SCN_MEM_READ) !== 0,
|
|
146
|
+
writable: (characteristics & IMAGE_SCN_MEM_WRITE) !== 0,
|
|
147
|
+
executable: (characteristics & IMAGE_SCN_MEM_EXECUTE) !== 0,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/** Parse image characteristics flags. */
|
|
151
|
+
export function parseImageCharacteristics(characteristics) {
|
|
152
|
+
const IMAGE_DLL = 0x2000;
|
|
153
|
+
const IMAGE_EXECUTABLE = 0x0002;
|
|
154
|
+
const IMAGE_CONSOLE = 0x0003;
|
|
155
|
+
const flags = [];
|
|
156
|
+
if (characteristics & IMAGE_DLL)
|
|
157
|
+
flags.push("DLL");
|
|
158
|
+
if (characteristics & IMAGE_EXECUTABLE)
|
|
159
|
+
flags.push("Executable");
|
|
160
|
+
if ((characteristics & 0x0000000f) === IMAGE_CONSOLE)
|
|
161
|
+
flags.push("Console");
|
|
162
|
+
return flags;
|
|
163
|
+
}
|
|
164
|
+
/** Parse a PE debug directory type. */
|
|
165
|
+
export function parseDebugType(type) {
|
|
166
|
+
switch (type) {
|
|
167
|
+
case 0:
|
|
168
|
+
return "UNKNOWN";
|
|
169
|
+
case 1:
|
|
170
|
+
return "COFF";
|
|
171
|
+
case 2:
|
|
172
|
+
return "CODEVIEW";
|
|
173
|
+
case 3:
|
|
174
|
+
return "POGO";
|
|
175
|
+
case 4:
|
|
176
|
+
return "MISC";
|
|
177
|
+
default:
|
|
178
|
+
return "UNKNOWN";
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Check if a PE manifest has PDB debug info. */
|
|
182
|
+
export function hasPdbInfo(manifest) {
|
|
183
|
+
return manifest.debug_entries.some((e) => e.pdb_guid !== null && e.pdb_path !== null);
|
|
184
|
+
}
|
|
185
|
+
/** Get all imported DLLs from a PE manifest. */
|
|
186
|
+
export function getImportedDlls(manifest) {
|
|
187
|
+
return [...new Set(manifest.imports.map((i) => i.dll))];
|
|
188
|
+
}
|
|
189
|
+
/** Get all exported function names from a PE manifest. */
|
|
190
|
+
export function getExportedFunctions(manifest) {
|
|
191
|
+
return manifest.exports.map((e) => e.name);
|
|
192
|
+
}
|
|
193
|
+
/** Count executable sections. */
|
|
194
|
+
export function countExecutableSections(manifest) {
|
|
195
|
+
return manifest.sections.filter((s) => s.characteristics.executable).length;
|
|
196
|
+
}
|
|
@@ -118,6 +118,8 @@ const replayTransitions = (scenario, run, observations, require) => {
|
|
|
118
118
|
while ((run.controls[controlIndex]?.after_capture_order ??
|
|
119
119
|
Number.MAX_SAFE_INTEGER) < observation.capture_order) {
|
|
120
120
|
const control = run.controls[controlIndex];
|
|
121
|
+
if (control === undefined)
|
|
122
|
+
break;
|
|
121
123
|
advanceControl(control, controlIndex);
|
|
122
124
|
controlIndex += 1;
|
|
123
125
|
}
|
|
@@ -125,6 +127,8 @@ const replayTransitions = (scenario, run, observations, require) => {
|
|
|
125
127
|
}
|
|
126
128
|
for (; controlIndex < run.controls.length; controlIndex += 1) {
|
|
127
129
|
const control = run.controls[controlIndex];
|
|
130
|
+
if (control === undefined)
|
|
131
|
+
break;
|
|
128
132
|
advanceControl(control, controlIndex);
|
|
129
133
|
}
|
|
130
134
|
require(transitionIndex ===
|
|
@@ -141,10 +145,11 @@ const validateControls = (run, observations, require) => {
|
|
|
141
145
|
require(control.sequence ===
|
|
142
146
|
index, `reactive_run.controls[${String(index)}].sequence`, "reactive control sequence must be contiguous");
|
|
143
147
|
require(admittedOrders.has(control.after_capture_order), `reactive_run.controls[${String(index)}].after_capture_order`, "reactive control cutoff must identify the last admitted observation");
|
|
148
|
+
const previous = run.controls.at(index - 1);
|
|
144
149
|
require(index === 0 ||
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.after_capture_order, `reactive_run.controls[${String(index)}].after_capture_order`, "reactive control cutoffs must be ordered");
|
|
150
|
+
(previous !== undefined &&
|
|
151
|
+
control.after_capture_order >=
|
|
152
|
+
previous.after_capture_order), `reactive_run.controls[${String(index)}].after_capture_order`, "reactive control cutoffs must be ordered");
|
|
148
153
|
}
|
|
149
154
|
};
|
|
150
155
|
/** Validate one capture's reactive journal by replaying the production reducer. */
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { validateProcessCaptureReactiveRun } from "./processCaptureReactiveValidation.js";
|
|
2
2
|
import { replayMachineSchema } from "./replayMachine.js";
|
|
3
3
|
import { digestProcessCommitment } from "./processScenario.js";
|
|
4
|
-
const orderedTimestamps = (values) => values.every((value, index) =>
|
|
4
|
+
const orderedTimestamps = (values) => values.every((value, index) => {
|
|
5
|
+
const previous = values[index - 1];
|
|
6
|
+
return previous === undefined || value.at_ms >= previous.at_ms;
|
|
7
|
+
});
|
|
8
|
+
const transitionsAreContiguous = (previous, current) => previous !== undefined && previous.state_after === current.state_before;
|
|
5
9
|
const validateCommitments = (capture, require) => {
|
|
6
10
|
const { manifest } = capture;
|
|
7
11
|
require(manifest.scenario.executable_sha256 ===
|
|
@@ -192,9 +196,9 @@ const validateReplayEvents = (capture, require) => {
|
|
|
192
196
|
if (index === 0)
|
|
193
197
|
require(transition.state_before ===
|
|
194
198
|
machine?.initial_state, "replay_transitions", "first replay transition does not start at the declared initial state");
|
|
199
|
+
const previous = capture.replay_transitions[index - 1];
|
|
195
200
|
if (index > 0)
|
|
196
|
-
require(
|
|
197
|
-
transition.state_before, "replay_transitions", "replay transition states are not contiguous");
|
|
201
|
+
require(transitionsAreContiguous(previous, transition), "replay_transitions", "replay transition states are not contiguous");
|
|
198
202
|
}
|
|
199
203
|
};
|
|
200
204
|
/** Recompute v4 commitments and cross-field invariants without side effects. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import canonicalize from "canonicalize";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
import { validateProcessCapture } from "./processCapture.js";
|
|
3
4
|
import { jsonValueSchema } from "./jsonValue.js";
|
|
@@ -97,6 +98,10 @@ const filesystemObservations = (capture) => [
|
|
|
97
98
|
effects: capture.filesystem_effects,
|
|
98
99
|
},
|
|
99
100
|
];
|
|
101
|
+
const sameJsonValue = (left, right) => {
|
|
102
|
+
const encodedLeft = canonicalize(left);
|
|
103
|
+
return encodedLeft !== undefined && encodedLeft === canonicalize(right);
|
|
104
|
+
};
|
|
100
105
|
/** Canonical observations for one process-comparison dimension. */
|
|
101
106
|
export const processDimensionObservations = (capture, dimension) => {
|
|
102
107
|
switch (dimension) {
|
|
@@ -117,7 +122,7 @@ export const processDimensionObservations = (capture, dimension) => {
|
|
|
117
122
|
}
|
|
118
123
|
};
|
|
119
124
|
const classifyCollection = (left, right) => {
|
|
120
|
-
if (
|
|
125
|
+
if (sameJsonValue(left, right))
|
|
121
126
|
return "unchanged";
|
|
122
127
|
if (left.length === 0)
|
|
123
128
|
return "added";
|
|
@@ -141,7 +146,7 @@ const firstCollectionDivergence = (dimension, left, right) => {
|
|
|
141
146
|
for (let index = 0; index < length; index += 1) {
|
|
142
147
|
const leftValue = left[index] ?? null;
|
|
143
148
|
const rightValue = right[index] ?? null;
|
|
144
|
-
if (
|
|
149
|
+
if (sameJsonValue(leftValue, rightValue))
|
|
145
150
|
continue;
|
|
146
151
|
return {
|
|
147
152
|
status: "found",
|
|
@@ -168,8 +173,9 @@ const assertComparable = (left, right, options) => {
|
|
|
168
173
|
...validateProcessCapture(left),
|
|
169
174
|
...validateProcessCapture(right),
|
|
170
175
|
];
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
const firstInvalid = invalid.at(0);
|
|
177
|
+
if (firstInvalid !== undefined)
|
|
178
|
+
throw new TypeError(`Invalid Process Capture v4: ${firstInvalid.path}`);
|
|
173
179
|
if (left.schema_version !== right.schema_version ||
|
|
174
180
|
left.manifest.comparison_contract_sha256 !==
|
|
175
181
|
right.manifest.comparison_contract_sha256)
|
|
@@ -239,8 +245,7 @@ const compareDimensions = (left, right, sameNormalization) => {
|
|
|
239
245
|
interaction: classify("interaction", left.interaction_events, right.interaction_events),
|
|
240
246
|
exit: hasUnknown(left, "exit") || hasUnknown(right, "exit")
|
|
241
247
|
? "unknown"
|
|
242
|
-
:
|
|
243
|
-
JSON.stringify({ exit: right.exit, settlement: right.settlement })
|
|
248
|
+
: sameJsonValue({ exit: left.exit, settlement: left.settlement }, { exit: right.exit, settlement: right.settlement })
|
|
244
249
|
? "unchanged"
|
|
245
250
|
: "changed",
|
|
246
251
|
filesystem: classify("filesystem", filesystemObservations(left), filesystemObservations(right)),
|
|
@@ -266,7 +271,7 @@ export const compareProcessCaptures = (left, right, options = {}) => {
|
|
|
266
271
|
trace: compareProcessTraces(left, right, options.traceSpecification),
|
|
267
272
|
};
|
|
268
273
|
}
|
|
269
|
-
const sameNormalization =
|
|
274
|
+
const sameNormalization = sameJsonValue(left.normalization, right.normalization);
|
|
270
275
|
const exactDimensions = compareDimensions(left, right, sameNormalization);
|
|
271
276
|
const trace = options.traceSpecification === undefined
|
|
272
277
|
? undefined
|
|
@@ -52,14 +52,13 @@ export const createProcessObservation = (input) => ({
|
|
|
52
52
|
const atMilliseconds = (value) => {
|
|
53
53
|
if (typeof value !== "object" || value === null)
|
|
54
54
|
return null;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return candidate;
|
|
60
|
-
}
|
|
55
|
+
if ("at_ms" in value && isSafeMillisecond(value.at_ms))
|
|
56
|
+
return value.at_ms;
|
|
57
|
+
if ("dispatched_at_ms" in value && isSafeMillisecond(value.dispatched_at_ms))
|
|
58
|
+
return value.dispatched_at_ms;
|
|
61
59
|
return null;
|
|
62
60
|
};
|
|
61
|
+
const isSafeMillisecond = (value) => typeof value === "number" && Number.isSafeInteger(value);
|
|
63
62
|
/** Derive the stable capture-local identity for one normalized observation. */
|
|
64
63
|
export const processObservationSubject = (source, value) => {
|
|
65
64
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|