mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 18:52:48 +00:00
fix(runtime): bind Inspector evidence to the selected request (#10039)
This commit is contained in:
1 parent
dd522bf9a7
commit
81d4f6b42a
2 files changed
+142
-34
No files matched your search
@@ -22,6 +22,41 @@ import {
|
||||
expectPreemptedCancellation,
|
||||
} from "../../../tests/fixtures/ownerObservationExpectation.js";
|
||||
|
||||
const runtimeObservation = javascriptRuntimeObservationSchema.parse({
|
||||
runtime: {
|
||||
product: "node.js/v24",
|
||||
protocol_version: "1.3",
|
||||
v8_version: "13",
|
||||
},
|
||||
target: {
|
||||
target_id: "target",
|
||||
protocol_type: "node",
|
||||
attached: false,
|
||||
location: { kind: "file", file_path: "/fixture.js" },
|
||||
runtime_kind: "node",
|
||||
runtime_kind_authority: "caller-declared-unverified",
|
||||
},
|
||||
capture: {
|
||||
observation_ms: 0,
|
||||
events_observed: 0,
|
||||
events_retained: 0,
|
||||
events_dropped: 0,
|
||||
metadata_bytes_retained: 0,
|
||||
truncated: false,
|
||||
truncation_reasons: [],
|
||||
},
|
||||
scripts: {
|
||||
items: [],
|
||||
observed_total: 0,
|
||||
excluded: { unsupported_location: 0, invalid_protocol_value: 0 },
|
||||
},
|
||||
execution_contexts: [],
|
||||
directly_observed: ["Inspector target attached and queried."],
|
||||
unavailable_without_instrumentation: [],
|
||||
unknowns: [],
|
||||
limitations: [],
|
||||
});
|
||||
|
||||
const observeCancelled = async (partial: unknown) => {
|
||||
const reason = { requested: "stop before runtime observation completed" };
|
||||
const failure = new AnalysisCancelledError("observe_javascript_runtime", {
|
||||
@@ -175,40 +210,7 @@ it("does not let late cancellation hide an invalid completed Inspector report",
|
||||
});
|
||||
|
||||
it("converts a raw runtime observation retained by cleanup failure", async () => {
|
||||
const observation = javascriptRuntimeObservationSchema.parse({
|
||||
runtime: {
|
||||
product: "node.js/v24",
|
||||
protocol_version: "1.3",
|
||||
v8_version: "13",
|
||||
},
|
||||
target: {
|
||||
target_id: "target",
|
||||
protocol_type: "node",
|
||||
attached: false,
|
||||
location: { kind: "file", file_path: "/fixture.js" },
|
||||
runtime_kind: "node",
|
||||
runtime_kind_authority: "caller-declared-unverified",
|
||||
},
|
||||
capture: {
|
||||
observation_ms: 0,
|
||||
events_observed: 0,
|
||||
events_retained: 0,
|
||||
events_dropped: 0,
|
||||
metadata_bytes_retained: 0,
|
||||
truncated: false,
|
||||
truncation_reasons: [],
|
||||
},
|
||||
scripts: {
|
||||
items: [],
|
||||
observed_total: 0,
|
||||
excluded: { unsupported_location: 0, invalid_protocol_value: 0 },
|
||||
},
|
||||
execution_contexts: [],
|
||||
directly_observed: ["Inspector target attached and queried."],
|
||||
unavailable_without_instrumentation: [],
|
||||
unknowns: [],
|
||||
limitations: [],
|
||||
});
|
||||
const observation = runtimeObservation;
|
||||
const failure = new BrowserObservationError(
|
||||
"observe_javascript_runtime",
|
||||
"cleanup_failed",
|
||||
@@ -239,6 +241,7 @@ it("converts a raw runtime observation retained by cleanup failure", async () =>
|
||||
{
|
||||
inspector_endpoint: "http://127.0.0.1:9229",
|
||||
target_id: "target",
|
||||
runtime_kind: "node",
|
||||
observation_ms: 0,
|
||||
},
|
||||
);
|
||||
@@ -349,3 +352,75 @@ it.each([{ scripts: [undefined] }, { elapsed_ms: Number.NaN }])(
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[
|
||||
"target",
|
||||
{
|
||||
...runtimeObservation,
|
||||
target: { ...runtimeObservation.target, target_id: "other-target" },
|
||||
},
|
||||
],
|
||||
[
|
||||
"window",
|
||||
{
|
||||
...runtimeObservation,
|
||||
capture: { ...runtimeObservation.capture, observation_ms: 1 },
|
||||
},
|
||||
],
|
||||
[
|
||||
"declared kind",
|
||||
{
|
||||
...runtimeObservation,
|
||||
target: {
|
||||
...runtimeObservation.target,
|
||||
runtime_kind: "unknown" as const,
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"kind authority",
|
||||
{
|
||||
...runtimeObservation,
|
||||
target: {
|
||||
...runtimeObservation.target,
|
||||
runtime_kind_authority: "not-declared" as const,
|
||||
},
|
||||
},
|
||||
],
|
||||
])(
|
||||
"does not attest a provider's changed %s as the selected runtime observation",
|
||||
async (_name, report) => {
|
||||
const input = {
|
||||
inspector_endpoint: "http://127.0.0.1:9229",
|
||||
target_id: "target",
|
||||
observation_ms: 0,
|
||||
runtime_kind: "node" as const,
|
||||
};
|
||||
const provider: JavaScriptRuntimeObservationPort = {
|
||||
identity: () => ({ id: "test", name: "Test", version: "1" }),
|
||||
listTargets: async () => {
|
||||
throw new Error("unused");
|
||||
},
|
||||
observe: async () => ok(report),
|
||||
};
|
||||
const completed = await observeJavaScriptRuntime(provider, input);
|
||||
expect(completed).toMatchObject({
|
||||
ok: false,
|
||||
error: { _tag: "AnalysisOutputError", partialObservation: report },
|
||||
});
|
||||
const primary = new AnalysisCancelledError("observe_javascript_runtime", {
|
||||
partialObservation: report,
|
||||
});
|
||||
const failed = await observeJavaScriptRuntime(
|
||||
{ ...provider, observe: async () => err(primary) },
|
||||
input,
|
||||
);
|
||||
expect(failed).toMatchObject({ ok: false, error: primary });
|
||||
expect(primary.partialObservation).toEqual(report);
|
||||
expect(primary.partialObservation).not.toHaveProperty("evidence_id");
|
||||
expect(primary.secondaryFailures).toMatchObject([
|
||||
{ _tag: "AnalysisOutputError" },
|
||||
]);
|
||||
},
|
||||
);
|
||||
@@ -11,6 +11,7 @@ import type { AnalysisError } from "../../domain/analysisErrorBase.js";
|
||||
import type {
|
||||
ListJavaScriptRuntimeTargetsInput,
|
||||
ObserveJavaScriptRuntimeInput,
|
||||
JavaScriptRuntimeObservation,
|
||||
} from "../../domain/javascript/javascriptRuntimeObservation.js";
|
||||
import { err, ok, type Result } from "../../domain/result.js";
|
||||
import {
|
||||
@@ -80,6 +81,17 @@ export const observeJavaScriptRuntime = async (
|
||||
) {
|
||||
const report = javascriptRuntimeObservationSchema.safeParse(partial);
|
||||
if (report.success) {
|
||||
const mismatch = runtimeSelectionFailure(input, report.data);
|
||||
if (mismatch !== undefined) {
|
||||
result.error.retainSecondaryFailure(mismatch);
|
||||
return err(
|
||||
keepIncompleteObservation(
|
||||
result.error,
|
||||
"observe_javascript_runtime",
|
||||
"Inspector retained a non-JSON incomplete observation.",
|
||||
),
|
||||
);
|
||||
}
|
||||
result.error.partialObservation =
|
||||
createJavaScriptRuntimeObservationEvidence(
|
||||
"observe_javascript_runtime",
|
||||
@@ -107,6 +119,9 @@ export const observeJavaScriptRuntime = async (
|
||||
{ cause: report.error },
|
||||
),
|
||||
);
|
||||
const mismatch = runtimeSelectionFailure(input, report.data);
|
||||
if (mismatch !== undefined)
|
||||
return err(mismatch.retainPartialObservation(report.data));
|
||||
return runtimeEvidence(
|
||||
"observe_javascript_runtime",
|
||||
input,
|
||||
@@ -116,6 +131,24 @@ export const observeJavaScriptRuntime = async (
|
||||
);
|
||||
};
|
||||
|
||||
/** Shape-valid observations still must identify the caller-selected request. */
|
||||
const runtimeSelectionFailure = (
|
||||
input: ObserveJavaScriptRuntimeInput,
|
||||
report: JavaScriptRuntimeObservation,
|
||||
): AnalysisOutputError | undefined =>
|
||||
report.target.target_id !== input.target_id ||
|
||||
report.capture.observation_ms !== input.observation_ms ||
|
||||
report.target.runtime_kind !== (input.runtime_kind ?? "unknown") ||
|
||||
report.target.runtime_kind_authority !==
|
||||
(input.runtime_kind === undefined
|
||||
? "not-declared"
|
||||
: "caller-declared-unverified")
|
||||
? new AnalysisOutputError(
|
||||
"observe_javascript_runtime",
|
||||
"Inspector changed the selected target, observation window, or caller-declared runtime kind.",
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const requireProvider = (
|
||||
provider: JavaScriptRuntimeObservationPort | undefined,
|
||||
operation: "list_javascript_runtime_targets" | "observe_javascript_runtime",
|
||||
|
||||
Reference in new issue
Block a user