fix(runtime): make observed target role optional

This commit is contained in:
morluto committed 2026-09-29 08:20:18 +08:00
1 parent 0ae3c0837b
commit 593a8e12ce
8 files changed
+56 -13

No files matched your search

@@ -52,7 +52,9 @@ const parameters = (
...("target_id" in input
? {
target_id: input.target_id,
runtime_kind: input.runtime_kind,
...(input.runtime_kind === undefined
? {}
: { runtime_kind: input.runtime_kind }),
observation_ms: input.observation_ms,
limits: input.limits,
}
+5 -2
View File
@@ -96,8 +96,11 @@ export const finalizeInspectorCapture = async ({
protocol_type: target.type,
attached: target.attached,
location: target.location,
runtime_kind: input.runtime_kind,
runtime_kind_authority: "caller-declared-unverified",
runtime_kind: input.runtime_kind ?? "unknown",
runtime_kind_authority:
input.runtime_kind === undefined
? "not-declared"
: "caller-declared-unverified",
},
capture: {
observation_ms: input.observation_ms,
+2 -1
View File
@@ -140,7 +140,8 @@ export class V8InspectorProvider implements JavaScriptRuntimeObservationPort {
options.signal,
);
const target = await authorizedTarget(discovery.targets, input, roots);
assertRuntimeKind(target, input.runtime_kind);
if (input.runtime_kind !== undefined)
assertRuntimeKind(target, input.runtime_kind);
connection = await CdpConnection.connect(
target.webSocketUrl,
"observe_javascript_runtime",
+5 -3
View File
@@ -41,9 +41,11 @@ const listOptionsSchema = z.object({ ...scopeOptions });
const observeOptionsSchema = z.object({
...scopeOptions,
runtimeKind: javascriptRuntimeKindSchema.describe(
"Declared target role; Inspector cannot authenticate the Electron role",
),
runtimeKind: javascriptRuntimeKindSchema
.optional()
.describe(
"Declared target role; Inspector cannot authenticate the Electron role",
),
observationMs: z
.number()
.int()
@@ -49,7 +49,6 @@ export const JAVASCRIPT_RUNTIME_OBSERVATION_TOOL_CONTRACTS = [
allowed_file_roots: [root],
allowed_origins: [],
target_id: "TARGET_ID_FROM_LIST_JAVASCRIPT_RUNTIME_TARGETS",
runtime_kind: "node",
approved: true,
observation_ms: 100,
limits: {
+9 -3
View File
@@ -69,6 +69,9 @@ export const javascriptRuntimeKindSchema = z.enum([
"electron-preload",
"electron-renderer",
]);
const observedJavaScriptRuntimeKindSchema = javascriptRuntimeKindSchema.or(
z.literal("unknown"),
);
export const javascriptRuntimeObservationLimitsSchema = z.strictObject({
max_events: z.number().int().min(1).max(50_000).default(10_000),
@@ -88,7 +91,7 @@ export const observeJavaScriptRuntimeInputSchema = z
.strictObject({
...approvedRuntimeScope,
target_id: z.string().trim().min(1).max(256),
runtime_kind: javascriptRuntimeKindSchema,
runtime_kind: javascriptRuntimeKindSchema.optional(),
observation_ms: z.number().int().min(0).max(10_000).default(100),
limits: javascriptRuntimeObservationLimitsSchema.default({
max_events: 10_000,
@@ -173,8 +176,11 @@ const javascriptRuntimeContextSchema = z.strictObject({
export const javascriptRuntimeObservationSchema = z.strictObject({
runtime: javascriptRuntimeVersionSchema,
target: javascriptRuntimeTargetSchema.extend({
runtime_kind: javascriptRuntimeKindSchema,
runtime_kind_authority: z.literal("caller-declared-unverified"),
runtime_kind: observedJavaScriptRuntimeKindSchema,
runtime_kind_authority: z.enum([
"caller-declared-unverified",
"not-declared",
]),
}),
capture: z.strictObject({
observation_ms: z.number().int().min(0),
@@ -284,13 +284,14 @@ const assertV8RuntimeParameters = (
.max(32),
allowed_origins: z.array(browserOriginSchema).max(32),
target_id: z.string().trim().min(1).max(256),
runtime_kind: javascriptRuntimeKindSchema,
runtime_kind: javascriptRuntimeKindSchema.optional(),
})
.passthrough()
.parse(evidence.parameters);
if (
parameters.target_id !== result.target.target_id ||
parameters.runtime_kind !== result.target.runtime_kind
(parameters.runtime_kind !== undefined &&
parameters.runtime_kind !== result.target.runtime_kind)
)
throw new TypeError(
"Runtime Evidence target or declared role disagrees with its result",
@@ -172,6 +172,35 @@ describe("passive V8 Inspector provider", () => {
);
});
describe("undeclared V8 runtime role", () => {
test("observes a target without inventing a runtime role", async () => {
const fixture = await runtimeFixture();
const fake = await startFakeV8Inspector({
targetUrl: pathToFileURL(fixture.entry).href,
targetType: "page",
});
try {
const input = observeInput(
fake.endpoint,
fake.targetId,
fixture.root,
"node",
);
delete input.runtime_kind;
const result = await new V8InspectorProvider().observe(input);
expect(result.ok).toBe(true);
if (!result.ok) return;
expect(result.value.target).toMatchObject({
protocol_type: "page",
runtime_kind: "unknown",
runtime_kind_authority: "not-declared",
});
} finally {
await fake.close();
}
});
});
describe("passive V8 Inspector evidence", () => {
test("marks capture truncation instead of claiming complete coverage", async () => {
const fixture = await runtimeFixture();