rea-agents 1.7.0 → 2.0.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.
Files changed (156) hide show
  1. package/README.md +38 -31
  2. package/dist/application/CapabilityInventory.js +18 -0
  3. package/dist/application/CrossVersionInvestigation.js +10 -6
  4. package/dist/application/Doctor.js +56 -6
  5. package/dist/application/ElectronBoundaryAnalysis.js +96 -0
  6. package/dist/application/ElectronBoundaryGraph.js +9 -0
  7. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  8. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  9. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  10. package/dist/application/ElectronBoundaryGraphWindows.js +199 -0
  11. package/dist/application/EnhancedTools.js +38 -13
  12. package/dist/application/InvestigationProviders.js +30 -0
  13. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  14. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  15. package/dist/application/JavaScriptApplicationService.js +74 -0
  16. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  17. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  18. package/dist/application/JavaScriptArtifactAnalysis.js +7 -1
  19. package/dist/application/JavaScriptArtifactGraphBuilder.js +59 -16
  20. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  21. package/dist/application/JavaScriptArtifactReconstruction.js +3 -0
  22. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  23. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  24. package/dist/application/JavaScriptReplayService.js +266 -0
  25. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  26. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  27. package/dist/application/ManagedApplicationGraphService.js +55 -0
  28. package/dist/application/ManagedMemberComparisonService.js +122 -0
  29. package/dist/application/ManagedNativeVerificationService.js +39 -0
  30. package/dist/application/ManagedReconstructionService.js +58 -0
  31. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  32. package/dist/application/PermissionAuthority.js +1 -1
  33. package/dist/application/ProcessSampling.js +15 -11
  34. package/dist/application/ProjectPermissionStore.js +1 -0
  35. package/dist/application/runtime.js +2 -0
  36. package/dist/browser/CdpCaptureEvents.js +49 -0
  37. package/dist/browser/CdpElectronInspection.js +106 -162
  38. package/dist/browser/CdpElectronProvider.js +5 -1
  39. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  40. package/dist/browser/CdpElectronScripts.js +94 -0
  41. package/dist/browser/CdpElectronWorkers.js +56 -0
  42. package/dist/browser/CdpPageCapture.js +8 -4
  43. package/dist/catalogIdentity.js +4 -1
  44. package/dist/cli.js +388 -0
  45. package/dist/cliApplicationCommands.js +62 -0
  46. package/dist/cliCommandNames.js +13 -0
  47. package/dist/cliElectronCommands.js +103 -1
  48. package/dist/cliJsonInput.js +54 -0
  49. package/dist/config.js +83 -0
  50. package/dist/contracts/applicationToolContracts.js +91 -0
  51. package/dist/contracts/artifactToolContracts.js +5 -9
  52. package/dist/contracts/browserToolContracts.js +14 -62
  53. package/dist/contracts/electronToolContracts.js +45 -19
  54. package/dist/contracts/errorSchemas.js +1 -0
  55. package/dist/contracts/investigationExamples.js +0 -6
  56. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  57. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  58. package/dist/contracts/managedToolContracts.js +153 -0
  59. package/dist/contracts/managedWorkflowExamples.js +346 -0
  60. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  61. package/dist/contracts/nativeToolContracts.js +2 -6
  62. package/dist/contracts/promptContracts.js +18 -2
  63. package/dist/contracts/toolContractExamples.js +10 -25
  64. package/dist/contracts/toolContracts.js +47 -45
  65. package/dist/contracts/toolEffects.js +160 -0
  66. package/dist/contracts/toolOutputSchemas.js +46 -31
  67. package/dist/doctorRuntime.js +42 -1
  68. package/dist/domain/artifactComparison.js +3 -4
  69. package/dist/domain/browserObservation.js +3 -0
  70. package/dist/domain/bundleComparison.js +4 -4
  71. package/dist/domain/electronObservation.js +13 -0
  72. package/dist/domain/electronStaticAnalysis.js +9 -0
  73. package/dist/domain/electronStaticAnalysisBrowser.js +194 -0
  74. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  75. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  76. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  77. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  78. package/dist/domain/errors.js +67 -1
  79. package/dist/domain/functionComparisonSchemas.js +3 -8
  80. package/dist/domain/inputIssueProjection.js +52 -0
  81. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  82. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  83. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  84. package/dist/domain/javascriptApplicationGraph.js +2 -1
  85. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  86. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  87. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  88. package/dist/domain/javascriptApplicationVersionItems.js +221 -0
  89. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  90. package/dist/domain/javascriptFeatureSeed.js +140 -0
  91. package/dist/domain/javascriptFeatureTrace.js +232 -0
  92. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  93. package/dist/domain/javascriptFeatureTraversal.js +88 -0
  94. package/dist/domain/javascriptNativeHandoff.js +85 -0
  95. package/dist/domain/javascriptReplay.js +361 -0
  96. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  97. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  98. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  99. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  100. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  101. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  102. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  103. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  104. package/dist/domain/javascriptRuntimeStaticCandidates.js +191 -0
  105. package/dist/domain/javascriptStaticAnalysis.js +31 -43
  106. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  107. package/dist/domain/javascriptStaticAnalysisHelpers.js +10 -0
  108. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  109. package/dist/domain/managedApplicationGraph.js +556 -0
  110. package/dist/domain/managedArtifact.js +444 -0
  111. package/dist/domain/managedMemberComparison.js +565 -0
  112. package/dist/domain/managedNativeVerification.js +408 -0
  113. package/dist/domain/managedReconstruction.js +183 -0
  114. package/dist/domain/managedRuntimeCorrelation.js +175 -0
  115. package/dist/domain/reconstructionVerificationSchemas.js +1 -3
  116. package/dist/dotnet/ManagedArtifactInspector.js +318 -0
  117. package/dist/dotnet/ManagedMemberInspector.js +887 -0
  118. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  119. package/dist/dotnet/ManagedMetadataInventory.js +368 -0
  120. package/dist/dotnet/ManagedMetadataLayout.js +322 -0
  121. package/dist/dotnet/ManagedNativeBoundaryInspector.js +391 -0
  122. package/dist/dotnet/ManagedPeReader.js +157 -0
  123. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  124. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  125. package/dist/generatedPackageMetadata.js +2 -2
  126. package/dist/ghidra/GhidraProvider.js +6 -0
  127. package/dist/main.js +14 -0
  128. package/dist/replay/JavaScriptReplayWorker.js +286 -0
  129. package/dist/replay/LinuxJavaScriptReplayRunner.js +434 -0
  130. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  131. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  132. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  133. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  134. package/dist/server/createServer.js +52 -0
  135. package/dist/server/registerApplicationTools.js +115 -0
  136. package/dist/server/registerArtifactComparisonTool.js +16 -9
  137. package/dist/server/registerBrowserTools.js +33 -8
  138. package/dist/server/registerBundleComparisonTool.js +17 -20
  139. package/dist/server/registerElectronTools.js +45 -3
  140. package/dist/server/registerEnhancedTools.js +58 -13
  141. package/dist/server/registerEvidenceTools.js +5 -1
  142. package/dist/server/registerFunctionComparisonTool.js +14 -7
  143. package/dist/server/registerInvestigationTools.js +21 -17
  144. package/dist/server/registerManagedTools.js +6 -0
  145. package/dist/server/registerManagedWorkflowTools.js +277 -0
  146. package/dist/server/registerOfficialTools.js +8 -8
  147. package/dist/server/registerProcessComparisonTool.js +25 -47
  148. package/dist/server/registerSessionStatusTool.js +7 -7
  149. package/dist/server/registerSessionTools.js +51 -86
  150. package/dist/server/sessionEvidence.js +14 -19
  151. package/dist/server/toolInputValidation.js +77 -0
  152. package/dist/server/toolRegistrationOptions.js +79 -2
  153. package/dist/server/toolResult.js +25 -17
  154. package/package.json +12 -4
  155. package/scripts/rea.mjs +1 -1
  156. package/skills/rea-analysis/SKILL.md +59 -3
@@ -0,0 +1,201 @@
1
+ import canonicalize from "canonicalize";
2
+ import { createHash } from "node:crypto";
3
+ const REPLAY_POLICY_VERSION = "linux-bwrap-systemd-v1";
4
+ const REPLAY_POLICY_DOCUMENT = Object.freeze({
5
+ version: REPLAY_POLICY_VERSION,
6
+ namespaces: ["user", "pid", "network", "ipc", "uts", "cgroup"],
7
+ capabilities: "drop-all",
8
+ network: "none",
9
+ filesystem: "minimal-read-only-runtime-plus-private-tmpfs",
10
+ seccomp: "rea-linux-x86_64-v1",
11
+ resource_manager: "systemd-user-cgroup-v2",
12
+ nested_user_namespaces: false,
13
+ });
14
+ /** Read, normalize, and content-address every input to one replay experiment. */
15
+ export const prepareReplayPlan = async (input, policy, host) => {
16
+ const cases = replayCases(input).map((item) => ({
17
+ ...item,
18
+ sha256: digestJson(item.arguments),
19
+ }));
20
+ if (new TextEncoder().encode(JSON.stringify(cases.map(({ arguments: args }) => args))).byteLength > input.limits.input_bytes)
21
+ throw new RangeError("Replay case inputs exceed the aggregate byte limit");
22
+ await host.probe(policy);
23
+ const [runtime, bubblewrap, systemdRun, systemctl, shell, worker, runtimeFiles, left, right,] = await Promise.all([
24
+ host.identifyExecutable(policy.nodePath, ["--version"]),
25
+ host.identifyExecutable(policy.bubblewrapPath, ["--version"]),
26
+ host.identifyExecutable(policy.systemdRunPath, ["--version"]),
27
+ host.identifyExecutable(policy.systemctlPath, ["--version"]),
28
+ host.identifyExecutable(policy.shellPath, ["--version"]),
29
+ host.identifyWorker(),
30
+ host.identifyRuntimeClosure(policy.nodePath),
31
+ prepareSide(input.left, input.limits.module_bytes, host),
32
+ input.right === undefined
33
+ ? Promise.resolve(undefined)
34
+ : prepareSide(input.right, input.limits.module_bytes, host),
35
+ ]);
36
+ const withoutDigest = {
37
+ schema_version: 1,
38
+ policy_version: REPLAY_POLICY_VERSION,
39
+ policy_sha256: digestJson(REPLAY_POLICY_DOCUMENT),
40
+ network: "none",
41
+ filesystem: {
42
+ host_writes: false,
43
+ private_tmpfs_bytes: input.limits.tmpfs_bytes,
44
+ },
45
+ runtime: {
46
+ executable: runtime,
47
+ worker,
48
+ read_only_files: runtimeFiles.map((item) => ({
49
+ source_path: item.sourcePath,
50
+ destination_path: item.destinationPath,
51
+ sha256: item.sha256,
52
+ })),
53
+ },
54
+ sandbox: {
55
+ bubblewrap,
56
+ systemd_run: systemdRun,
57
+ systemctl,
58
+ shell,
59
+ seccomp_sha256: host.seccompDigest(),
60
+ },
61
+ left: left.commitment,
62
+ ...(right === undefined ? {} : { right: right.commitment }),
63
+ cases,
64
+ determinism: input.determinism,
65
+ limits: input.limits,
66
+ effects: [
67
+ "Execute selected extracted modules in a disposable Linux OS sandbox",
68
+ "Create and remove one private cgroup and mount namespace",
69
+ "Retain bounded return, exception, termination, and diagnostic evidence",
70
+ "Perform no host filesystem writes and expose no host or external network",
71
+ ...(input.reproducer_export === undefined
72
+ ? []
73
+ : ["Write one separately approved reproducer after sandbox cleanup"]),
74
+ ],
75
+ reproducer_export: input.reproducer_export === undefined
76
+ ? null
77
+ : {
78
+ path: input.reproducer_export.path,
79
+ include_sources: input.reproducer_export.include_sources,
80
+ authority: "evidence_write",
81
+ },
82
+ };
83
+ const publicPlan = {
84
+ ...withoutDigest,
85
+ plan_digest: digestJson(withoutDigest),
86
+ };
87
+ return {
88
+ publicPlan,
89
+ leftSources: left.sources,
90
+ ...(right === undefined ? {} : { rightSources: right.sources }),
91
+ };
92
+ };
93
+ const prepareSide = async (side, maximumBytes, host) => {
94
+ const aliases = new Set(side.modules.map(({ alias }) => alias));
95
+ if (aliases.size !== side.modules.length || !aliases.has(side.entry_alias))
96
+ throw new TypeError("Replay manifest aliases or entry alias are invalid");
97
+ for (const module of side.modules)
98
+ for (const dependency of Object.values(module.dependencies))
99
+ if (!aliases.has(dependency))
100
+ throw new TypeError(`Undeclared replay dependency alias: ${dependency}`);
101
+ const loaded = [];
102
+ let totalBytes = 0;
103
+ for (const module of side.modules) {
104
+ const remaining = maximumBytes - totalBytes;
105
+ if (remaining <= 0)
106
+ throw new RangeError("Replay module bytes exceed the aggregate limit");
107
+ const source = await host.readSource(module.path, remaining);
108
+ totalBytes += source.bytes.byteLength;
109
+ loaded.push({ module, source });
110
+ }
111
+ return {
112
+ commitment: {
113
+ modules: loaded.map(({ module, source }) => ({
114
+ alias: module.alias,
115
+ canonical_path: source.canonicalPath,
116
+ format: module.format,
117
+ role: module.role,
118
+ byte_count: source.bytes.byteLength,
119
+ sha256: digestBytes(source.bytes),
120
+ dependencies: module.dependencies,
121
+ })),
122
+ entry_alias: side.entry_alias,
123
+ entry_export: side.entry_export,
124
+ },
125
+ sources: Object.fromEntries(loaded.map(({ module, source }) => [
126
+ module.alias,
127
+ new TextDecoder("utf-8", { fatal: true }).decode(source.bytes),
128
+ ])),
129
+ };
130
+ };
131
+ const replayCases = (input) => {
132
+ const explicit = input.cases.map((item) => ({
133
+ case_id: item.case_id,
134
+ arguments: item.arguments,
135
+ }));
136
+ if (input.generator === undefined)
137
+ return uniqueCases(explicit);
138
+ let state = input.generator.seed || 0x9e37_79b9;
139
+ const next = () => {
140
+ state ^= state << 13;
141
+ state ^= state >>> 17;
142
+ state ^= state << 5;
143
+ return state >>> 0;
144
+ };
145
+ const corpus = boundaryCorpus(input.generator.preset);
146
+ const generated = Array.from({ length: input.generator.count }, (_, index) => ({
147
+ case_id: `generated-${input.generator?.preset ?? "boundary"}-${String(index)}`,
148
+ arguments: [corpus[next() % corpus.length] ?? ""],
149
+ }));
150
+ return uniqueCases([...explicit, ...generated]);
151
+ };
152
+ const uniqueCases = (cases) => {
153
+ const ids = new Set();
154
+ for (const item of cases) {
155
+ if (ids.has(item.case_id))
156
+ throw new TypeError(`Duplicate replay case ID: ${item.case_id}`);
157
+ ids.add(item.case_id);
158
+ }
159
+ return cases;
160
+ };
161
+ const boundaryCorpus = (preset) => {
162
+ if (preset === "sanitizer-boundaries")
163
+ return [
164
+ "",
165
+ "<script>alert(1)</script>",
166
+ "<img src=x onerror=alert(1)>",
167
+ "javascript:alert(1)",
168
+ "<b>ok</b>",
169
+ "\u0000",
170
+ ];
171
+ if (preset === "clipboard-boundaries")
172
+ return [
173
+ "",
174
+ "plain",
175
+ "a\r\nb",
176
+ "a\nb",
177
+ "\t",
178
+ "😀",
179
+ "text/html",
180
+ "text/plain",
181
+ ];
182
+ return [
183
+ "",
184
+ " ",
185
+ "\n",
186
+ "# heading",
187
+ "**bold**",
188
+ "[x](javascript:y)",
189
+ "`code`",
190
+ "😀",
191
+ "\u0000",
192
+ "a".repeat(1024),
193
+ ];
194
+ };
195
+ export const digestBytes = (value) => createHash("sha256").update(value).digest("hex");
196
+ export const digestJson = (value) => {
197
+ const encoded = canonicalize(value);
198
+ if (encoded === undefined)
199
+ throw new TypeError("Replay commitment is not canonical JSON");
200
+ return createHash("sha256").update(encoded).digest("hex");
201
+ };
@@ -0,0 +1,266 @@
1
+ import { z } from "zod";
2
+ import writeFileAtomic from "write-file-atomic";
3
+ import { controlledReplayInputSchema, replayExecutionResultSchema, controlledReplayOutputSchema, replayEvidenceSchema, } from "../domain/javascriptReplay.js";
4
+ import { AnalysisCapabilityUnavailableError, AnalysisCancelledError, AnalysisInputError, AnalysisProtocolError, PermissionRequiredError, ReplayPlanStaleError, } from "../domain/errors.js";
5
+ import { createEvidence } from "../domain/evidence.js";
6
+ import { projectInputIssues } from "../domain/inputIssueProjection.js";
7
+ import { jsonValueSchema } from "../domain/jsonValue.js";
8
+ import { err, ok } from "../domain/result.js";
9
+ import { digestBytes, prepareReplayPlan, } from "./JavaScriptReplayPlanning.js";
10
+ const OPERATION = "run_controlled_replay";
11
+ const isAborted = (signal) => signal?.aborted === true;
12
+ /** Plan or execute one content-bound extracted-module replay experiment. */
13
+ export const runControlledReplay = async (dependencies, rawInput, options = {}) => {
14
+ const parsed = controlledReplayInputSchema.safeParse(rawInput);
15
+ if (!parsed.success)
16
+ return err(new AnalysisInputError(OPERATION, { cause: parsed.error }, projectInputIssues(parsed.error.issues, rawInput)));
17
+ return runControlledReplayValidated(dependencies, parsed.data, options);
18
+ };
19
+ /** Plan or execute replay input already parsed by a trusted adapter. */
20
+ export const runControlledReplayValidated = async (dependencies, input, options = {}) => {
21
+ if (!dependencies.policy.enabled)
22
+ return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "controlled replay is disabled; configure exact roots and executables before enabling it"));
23
+ if (dependencies.authority === undefined)
24
+ return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, "JavaScript replay permission policy is not configured"));
25
+ if (isAborted(options.signal))
26
+ return err(new AnalysisCancelledError(OPERATION));
27
+ const request = permissionRequest(input, dependencies.policy);
28
+ const authorized = input.mode === "plan"
29
+ ? await dependencies.authority.explain(request, "read")
30
+ : await dependencies.authority.authorize(request, "read");
31
+ if (!authorized.ok)
32
+ return err(authorized.error instanceof PermissionRequiredError
33
+ ? authorized.error
34
+ : new AnalysisProtocolError(authorized.error.message, {
35
+ cause: authorized.error,
36
+ }));
37
+ let prepared;
38
+ try {
39
+ prepared = await prepareReplayPlan(input, dependencies.policy, dependencies.host);
40
+ }
41
+ catch (cause) {
42
+ return err(new AnalysisCapabilityUnavailableError("rea-javascript-replay", OPERATION, cause instanceof Error ? cause.message : "replay planning failed"));
43
+ }
44
+ if (isAborted(options.signal))
45
+ return err(new AnalysisCancelledError(OPERATION));
46
+ if (input.mode === "plan")
47
+ return ok(asJson({
48
+ phase: "plan",
49
+ plan: prepared.publicPlan,
50
+ source_evidence: [],
51
+ evidence: null,
52
+ }));
53
+ if (input.plan_digest !== prepared.publicPlan.plan_digest)
54
+ return err(new ReplayPlanStaleError(input.plan_digest ?? "", prepared.publicPlan.plan_digest));
55
+ let canonicalExportPath;
56
+ if (input.reproducer_export !== undefined) {
57
+ if (input.reproducer_export.approved !== true)
58
+ return err(new AnalysisInputError(`${OPERATION}:reproducer_export`));
59
+ const exportAuthorized = await dependencies.authority.authorize({
60
+ capability: "evidence_write",
61
+ roots: [input.reproducer_export.path],
62
+ executables: [],
63
+ environment_names: [],
64
+ network: "none",
65
+ mount: false,
66
+ operation_identity: `${OPERATION}:reproducer:${prepared.publicPlan.plan_digest}`,
67
+ }, "write");
68
+ if (!exportAuthorized.ok)
69
+ return err(exportAuthorized.error instanceof PermissionRequiredError
70
+ ? exportAuthorized.error
71
+ : new AnalysisProtocolError(exportAuthorized.error.message, {
72
+ cause: exportAuthorized.error,
73
+ }));
74
+ canonicalExportPath = exportAuthorized.value.request.roots[0];
75
+ if (canonicalExportPath !== input.reproducer_export.path)
76
+ return err(new AnalysisInputError(`${OPERATION}:reproducer_export:path`, {
77
+ cause: new TypeError(`Use the canonical reproducer path: ${canonicalExportPath ?? "unavailable"}`),
78
+ }));
79
+ }
80
+ if (isAborted(options.signal))
81
+ return err(new AnalysisCancelledError(OPERATION));
82
+ await options.progress?.report({
83
+ phase: OPERATION,
84
+ completed: 0,
85
+ total: 1,
86
+ message: "Admitting approved modules into the isolated replay worker",
87
+ });
88
+ if (isAborted(options.signal))
89
+ return err(new AnalysisCancelledError(OPERATION));
90
+ try {
91
+ let executed = replayExecutionResultSchema.parse(await dependencies.runner.execute(prepared, dependencies.policy, options.signal));
92
+ await options.progress?.report({
93
+ phase: OPERATION,
94
+ completed: 1,
95
+ total: 1,
96
+ message: "Controlled replay stopped and sandbox cleanup was observed",
97
+ terminal: true,
98
+ });
99
+ if (executed.termination === "cancelled")
100
+ return err(new AnalysisCancelledError(OPERATION));
101
+ if (input.reproducer_export !== undefined &&
102
+ canonicalExportPath !== undefined &&
103
+ executed.cleanup.state === "complete") {
104
+ const manifest = {
105
+ schema_version: 1,
106
+ plan: prepared.publicPlan,
107
+ result: executed,
108
+ sources: input.reproducer_export.include_sources
109
+ ? {
110
+ left: prepared.leftSources,
111
+ ...(prepared.rightSources === undefined
112
+ ? {}
113
+ : { right: prepared.rightSources }),
114
+ }
115
+ : null,
116
+ };
117
+ const encoded = Buffer.from(`${JSON.stringify(manifest, null, 2)}\n`);
118
+ try {
119
+ await writeFileAtomic(canonicalExportPath, encoded, {
120
+ mode: 0o600,
121
+ });
122
+ executed = replayExecutionResultSchema.parse({
123
+ ...executed,
124
+ reproducer: {
125
+ state: "written",
126
+ path: canonicalExportPath,
127
+ sha256: digestBytes(encoded),
128
+ },
129
+ });
130
+ }
131
+ catch (cause) {
132
+ executed = replayExecutionResultSchema.parse({
133
+ ...executed,
134
+ limitations: [
135
+ ...executed.limitations,
136
+ "Replay completed, but the separately approved reproducer export failed.",
137
+ ],
138
+ reproducer: {
139
+ state: "failed",
140
+ path: canonicalExportPath,
141
+ error: cause instanceof Error
142
+ ? cause.message
143
+ : "unknown reproducer export failure",
144
+ },
145
+ });
146
+ }
147
+ }
148
+ const leftCount = prepared.publicPlan.cases.length;
149
+ const sourceEvidence = [
150
+ createReplayEvidence(prepared, executed, "left", executed.outcomes.slice(0, leftCount)),
151
+ ...(prepared.publicPlan.right === undefined
152
+ ? []
153
+ : [
154
+ createReplayEvidence(prepared, executed, "right", executed.outcomes.slice(leftCount)),
155
+ ]),
156
+ ];
157
+ const subject = prepared.publicPlan.left.modules[0];
158
+ const evidence = createEvidence(subject === undefined
159
+ ? undefined
160
+ : {
161
+ path: subject.canonical_path,
162
+ sha256: subject.sha256,
163
+ format: "javascript",
164
+ }, {
165
+ id: "rea-javascript-replay",
166
+ name: "REA isolated JavaScript replay",
167
+ version: "1",
168
+ }, {
169
+ predicateType: "javascript-controlled-replay",
170
+ operation: OPERATION,
171
+ parameters: {
172
+ replay_plan: jsonValueSchema.parse(JSON.parse(JSON.stringify(prepared.publicPlan))),
173
+ },
174
+ result: jsonValueSchema.parse(JSON.parse(JSON.stringify(executed))),
175
+ rawResult: jsonValueSchema.parse(JSON.parse(JSON.stringify({
176
+ cases: prepared.publicPlan.cases,
177
+ outcomes: executed.outcomes,
178
+ stderr: executed.stderr,
179
+ }))),
180
+ confidence: executed.comparison === undefined ? "observed" : "derived",
181
+ authority: "controlled-replay",
182
+ environment: {
183
+ id: prepared.publicPlan.plan_digest,
184
+ platform: process.platform,
185
+ architecture: process.arch,
186
+ isolation: "container",
187
+ },
188
+ limitations: executed.limitations,
189
+ locations: prepared.publicPlan.left.modules.map((module) => ({
190
+ kind: "artifact-path",
191
+ path: module.canonical_path,
192
+ })),
193
+ evidenceLinks: sourceEvidence.map(({ evidence_id: id }) => id),
194
+ });
195
+ return ok(asJson({
196
+ phase: "execute",
197
+ plan: null,
198
+ source_evidence: sourceEvidence.map((item) => replayEvidenceSchema.parse(item)),
199
+ evidence: replayEvidenceSchema.parse(evidence),
200
+ }));
201
+ }
202
+ catch (cause) {
203
+ return err(new AnalysisProtocolError(cause instanceof z.ZodError
204
+ ? "Controlled replay produced an invalid bounded result"
205
+ : "Controlled replay could not establish or clean up its sandbox", { cause }));
206
+ }
207
+ };
208
+ const createReplayEvidence = (prepared, executed, side, outcomes) => {
209
+ const manifest = side === "left" ? prepared.publicPlan.left : prepared.publicPlan.right;
210
+ const subject = manifest?.modules[0];
211
+ const result = replayExecutionResultSchema.parse({
212
+ ...executed,
213
+ outcomes,
214
+ comparison: undefined,
215
+ reproducer: null,
216
+ });
217
+ return createEvidence(subject === undefined
218
+ ? undefined
219
+ : {
220
+ path: subject.canonical_path,
221
+ sha256: subject.sha256,
222
+ format: "javascript",
223
+ }, {
224
+ id: "rea-javascript-replay",
225
+ name: "REA isolated JavaScript replay",
226
+ version: "1",
227
+ }, {
228
+ predicateType: "javascript-controlled-replay-observation",
229
+ operation: OPERATION,
230
+ parameters: {
231
+ replay_plan: jsonValueSchema.parse(JSON.parse(JSON.stringify(prepared.publicPlan))),
232
+ side,
233
+ },
234
+ result: jsonValueSchema.parse(JSON.parse(JSON.stringify(result))),
235
+ rawResult: jsonValueSchema.parse(JSON.parse(JSON.stringify({ cases: prepared.publicPlan.cases, outcomes }))),
236
+ confidence: "observed",
237
+ authority: "controlled-replay",
238
+ environment: {
239
+ id: prepared.publicPlan.plan_digest,
240
+ platform: process.platform,
241
+ architecture: process.arch,
242
+ isolation: "container",
243
+ },
244
+ limitations: executed.limitations,
245
+ locations: (manifest?.modules ?? []).map((module) => ({
246
+ kind: "artifact-path",
247
+ path: module.canonical_path,
248
+ })),
249
+ });
250
+ };
251
+ const asJson = (value) => jsonValueSchema.parse(JSON.parse(JSON.stringify(controlledReplayOutputSchema.parse(value))));
252
+ const permissionRequest = (input, policy) => ({
253
+ capability: "javascript_replay",
254
+ roots: [...input.left.modules, ...(input.right?.modules ?? [])].map(({ path }) => path),
255
+ executables: [
256
+ policy.nodePath,
257
+ policy.bubblewrapPath,
258
+ policy.systemdRunPath,
259
+ policy.systemctlPath,
260
+ policy.shellPath,
261
+ ],
262
+ environment_names: [],
263
+ network: "none",
264
+ mount: true,
265
+ operation_identity: `${OPERATION}:${input.plan_digest ?? "plan"}`,
266
+ });
@@ -0,0 +1,25 @@
1
+ import { createEvidence, } from "../domain/evidence.js";
2
+ import { jsonValueSchema } from "../domain/jsonValue.js";
3
+ import { JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER } from "./InvestigationProviders.js";
4
+ /** Create derived Evidence v2 for one exact set of static/runtime inputs. */
5
+ export const createJavaScriptRuntimeReconciliationEvidence = (input, result) => createEvidence(undefined, JAVASCRIPT_RUNTIME_RECONCILIATION_PROVIDER, {
6
+ predicateType: "rea.javascript-runtime-reconciliation/v1",
7
+ operation: "reconcile_javascript_runtime",
8
+ parameters: parameters(input),
9
+ result: jsonValueSchema.parse(result),
10
+ rawResult: null,
11
+ confidence: "inferred",
12
+ authority: "analyst-inference",
13
+ environment: null,
14
+ limitations: result.limitations,
15
+ evidenceLinks: result.evidence_links,
16
+ });
17
+ const parameters = (input) => ({
18
+ static_layers: input.static_layers.map((layer) => ({
19
+ role: layer.role,
20
+ evidence_id: layer.analysis.evidence_id,
21
+ runtime_mappings: layer.runtime_mappings,
22
+ })),
23
+ runtime_evidence_ids: input.runtime_observations.map(({ evidence_id: id }) => id),
24
+ limits: input.limits,
25
+ });
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
3
+ import { projectInputIssues } from "../domain/inputIssueProjection.js";
4
+ import { reconcileJavaScriptRuntime } from "../domain/javascriptRuntimeReconciliation.js";
5
+ import { reconcileJavaScriptRuntimeInputSchema } from "../domain/javascriptRuntimeReconciliationSchemas.js";
6
+ import { err, ok } from "../domain/result.js";
7
+ import { createJavaScriptRuntimeReconciliationEvidence } from "./JavaScriptRuntimeReconciliationEvidence.js";
8
+ const OPERATION = "reconcile_javascript_runtime";
9
+ /** Derive a combined JAG from verified static and passive-runtime Evidence. */
10
+ export const reconcileJavaScriptRuntimeEvidence = (rawInput) => {
11
+ const parsed = reconcileJavaScriptRuntimeInputSchema.safeParse(rawInput);
12
+ if (!parsed.success)
13
+ return err(new AnalysisInputError(OPERATION, undefined, projectInputIssues(parsed.error.issues, rawInput)));
14
+ return reconcileJavaScriptRuntimeEvidenceValidated(parsed.data);
15
+ };
16
+ /** Reconcile input already parsed by a trusted adapter boundary. */
17
+ export const reconcileJavaScriptRuntimeEvidenceValidated = (input) => {
18
+ try {
19
+ const result = reconcileJavaScriptRuntime(input);
20
+ return ok(createJavaScriptRuntimeReconciliationEvidence(input, result));
21
+ }
22
+ catch (cause) {
23
+ return err(cause instanceof z.ZodError || cause instanceof TypeError
24
+ ? new AnalysisInputError(OPERATION)
25
+ : new AnalysisProtocolError("JavaScript runtime reconciliation produced an invalid result", { cause }));
26
+ }
27
+ };
@@ -0,0 +1,55 @@
1
+ import { z } from "zod";
2
+ import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js";
3
+ import { createEvidence } from "../domain/evidence.js";
4
+ import { jsonValueSchema } from "../domain/jsonValue.js";
5
+ import { managedApplicationGraphResultSchema, projectManagedApplicationGraph, projectManagedApplicationGraphInputSchema, } from "../domain/managedApplicationGraph.js";
6
+ import { err, ok } from "../domain/result.js";
7
+ import { MANAGED_WORKFLOW_PROVIDER } from "./InvestigationProviders.js";
8
+ const OPERATION = "project_managed_application_graph";
9
+ /** Project authenticated managed Evidence into a provider-neutral graph. */
10
+ export const projectManagedApplicationGraphEvidence = (rawInput) => {
11
+ const parsed = projectManagedApplicationGraphInputSchema.safeParse(rawInput);
12
+ if (!parsed.success)
13
+ return err(new AnalysisInputError(OPERATION, { cause: parsed.error }));
14
+ try {
15
+ const result = projectManagedApplicationGraph(parsed.data);
16
+ return ok(createManagedApplicationGraphEvidence(parsed.data, result));
17
+ }
18
+ catch (cause) {
19
+ return err(cause instanceof TypeError || cause instanceof z.ZodError
20
+ ? new AnalysisInputError(OPERATION, { cause })
21
+ : new AnalysisProtocolError("Managed application graph projection produced an invalid result", { cause }));
22
+ }
23
+ };
24
+ const createManagedApplicationGraphEvidence = (input, result) => createEvidence(subjectTarget(input), MANAGED_WORKFLOW_PROVIDER, {
25
+ predicateType: "rea.managed-application-graph/v1",
26
+ operation: OPERATION,
27
+ parameters: {
28
+ managed_artifact_evidence_id: input.managed_artifact?.evidence_id ?? null,
29
+ managed_members_evidence_id: input.managed_members?.evidence_id ?? null,
30
+ managed_native_boundaries_evidence_id: input.managed_native_boundaries?.evidence_id ?? null,
31
+ limits: jsonValueSchema.parse(input.limits),
32
+ },
33
+ result: jsonValueSchema.parse(managedApplicationGraphResultSchema.parse(result)),
34
+ rawResult: null,
35
+ confidence: "inferred",
36
+ authority: "analyst-inference",
37
+ environment: null,
38
+ limitations: result.limitations,
39
+ evidenceLinks: result.evidence_links,
40
+ });
41
+ const subjectTarget = (input) => {
42
+ const subject = input.managed_artifact?.subject ??
43
+ input.managed_members?.subject ??
44
+ input.managed_native_boundaries?.subject;
45
+ if (subject === undefined || subject === null || subject.format !== "pe")
46
+ return undefined;
47
+ return {
48
+ path: subject.local_path,
49
+ sha256: subject.digest.sha256,
50
+ format: "pe",
51
+ ...(subject.architecture === null
52
+ ? {}
53
+ : { architecture: subject.architecture }),
54
+ };
55
+ };