Files
reverse-engineering-anything/src/domain/javascript/staticObservedEndpoints.test.ts
T
gensokyo-dev 3708538e85 feat(javascript): compare static endpoints with HAR captures (#9090)
* feat(javascript): compare static endpoints with HAR captures

* test(javascript): preserve original HAR fixture bytes during formatting

* test(javascript): load the byte-preserved HAR fixture
2026-11-06 13:34:26 +08:00

297 lines
9.5 KiB
TypeScript

import { expect, it } from "vitest";
import {
createJavaScriptApplicationGraph,
createJavaScriptApplicationNode,
} from "./javascriptApplicationGraph.js";
import { JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE } from "../../contracts/javascript/javascriptRuntimeReconciliationExample.js";
import { javascriptApplicationAnalysisResultSchema } from "./javascriptApplicationAnalysis.js";
import { analysisViewCaptureFixture } from "../../../tests/fixtures/analysisView.js";
import { WebNetworkApiSurfaceAccumulator } from "../analysisView/WebNetworkApiSurfaceAccumulator.js";
import { compareStaticObservedEndpoints } from "./staticObservedEndpoints.js";
import { staticObservedEndpointComparisonSchema } from "./staticObservedEndpointSchemas.js";
const original = javascriptApplicationAnalysisResultSchema.parse(
JAVASCRIPT_APPLICATION_EVIDENCE_EXAMPLE.normalized_result,
).graph;
const evidence = original.nodes[0]!.observations[0]!.evidence;
if (!evidence.artifact.available)
throw new Error("Static fixture must identify its source bytes");
const artifactSha256 = evidence.artifact.sha256;
const graphFor = (
targets: readonly {
value: string;
mechanism?: string;
interpretation?: string;
resolution?: string;
}[],
sourceState: "observed" | "unknown" = "observed",
) =>
createJavaScriptApplicationGraph({
schema: original.schema,
root_node_ids: original.root_node_ids,
coverage: original.coverage,
limitations: original.limitations,
nodes: [
...original.nodes,
...targets.map((target, index) =>
createJavaScriptApplicationNode({
kind: "endpoint",
identity: {
strategy: "artifact-local-key",
stability: "artifact-version",
artifact_sha256: artifactSha256,
namespace: "network-endpoint",
key: String(index),
},
observations: [
{
label: null,
properties: {
endpoint_kind: "network",
mechanism: "call:fetch",
...target,
},
evidence:
sourceState === "observed"
? evidence
: {
...evidence,
state: sourceState,
confidence: "unknown",
limitations: [
"Fixture explicitly leaves network interpretation unknown.",
],
},
},
],
}),
),
],
edges: [],
});
const run = (
targets: Parameters<typeof graphFor>[0],
requests: readonly { path: string; method?: string; origin?: string }[],
options: {
complete?: boolean;
origin?: string | null;
budget?: number;
sourceState?: "observed" | "unknown";
} = {},
) => {
const accumulator = new WebNetworkApiSurfaceAccumulator(
options.budget,
false,
{ operation: "compare_static_and_observed_endpoints" },
);
for (const [ordinal, request] of requests.entries()) {
const added = accumulator.add({
...analysisViewCaptureFixture().records[0]!,
ordinal,
limitations: [],
reported: {
request: {
method: request.method ?? "GET",
url: `${request.origin ?? "https://api.test"}${request.path}`,
},
response: { status: 200, content: { mimeType: "application/json" } },
},
});
if (!added.ok) return added;
}
return compareStaticObservedEndpoints({
applicationEvidenceId: `ev_${"a".repeat(64)}`,
captureEvidenceId: `ev_${"b".repeat(64)}`,
graph: graphFor(targets, options.sourceState),
accumulator,
captureComplete: options.complete ?? true,
...(options.origin === null
? {}
: { origin: options.origin ?? "https://api.test" }),
});
};
it("reports all four outcomes, exact/template basis and unknown method without copying URL details", () => {
const result = run(
[
{ value: "/matched?source-query=ordinary#fragment" },
{ value: "/users/789" },
{ value: "/missing" },
{ value: "KEY", interpretation: "candidate" },
],
[
{ path: "/matched?capture-query=ordinary" },
{ path: "/users/123" },
{ path: "/observed-only" },
],
);
if (!result.ok) throw result.error;
expect(result.value.summary).toMatchObject({
matched: 2,
not_observed_in_capture: 1,
unknown: 1,
observed_without_static_match: 1,
});
expect(result.value.matches.map(({ basis }) => basis).sort()).toEqual([
"exact",
"template-compatible",
]);
expect(
result.value.static_endpoints.find(({ path }) => path === "/matched"),
).toMatchObject({
method: null,
method_basis: "unknown",
origin_basis: "caller-origin",
});
expect(JSON.stringify(result.value)).not.toMatch(
/source-query|capture-query|fragment|ordinary/,
);
expect(
staticObservedEndpointComparisonSchema.shape.static_endpoints.safeParse(
result.value.static_endpoints,
).success,
).toBe(true);
});
it("does not promote an explicitly unknown static observation to a match", () => {
const result = run([{ value: "/matched" }], [{ path: "/matched" }], {
sourceState: "unknown",
});
if (!result.ok) throw result.error;
expect(result.value.static_endpoints[0]).toMatchObject({
status: "unknown",
reason: "unconfirmed-static-observation",
});
expect(result.value.matches).toEqual([]);
});
it("does not manufacture an exact whole path from independent templated segment values", () => {
const result = run(
[{ value: "/a/1/b/2" }],
[{ path: "/a/1/b/3" }, { path: "/a/4/b/2" }],
);
if (!result.ok) throw result.error;
expect(result.value.matches[0]?.basis).toBe("template-compatible");
expect(result.value.observed_groups[0]?.record_ordinals).toEqual([0, 1]);
});
it("names a concrete exact witness within a group containing different literal paths", () => {
const result = run(
[{ value: "/users/123" }],
[{ path: "/users/456" }, { path: "/users/123" }],
);
if (!result.ok) throw result.error;
expect(result.value.matches[0]).toMatchObject({
basis: "exact",
supporting_record_ordinal: 1,
});
expect(result.value.observed_groups[0]?.record_ordinals).toEqual([0, 1]);
});
it.each([{ complete: false }, { origin: null }])(
"keeps missing endpoints unknown with incomplete capture or undeclared origin: %j",
(options) => {
const result = run([{ value: "/missing" }], [{ path: "/other" }], options);
if (!result.ok) throw result.error;
expect(result.value.static_endpoints[0]?.status).toBe("unknown");
},
);
it("requires an exercised origin, even for an exact absolute URL", () => {
const result = run(
[{ value: "https://unseen.test/missing" }],
[{ path: "/other" }],
);
if (!result.ok) throw result.error;
expect(result.value.static_endpoints[0]).toMatchObject({
status: "unknown",
reason: "origin-not-exercised",
});
});
it("keeps normalization, operation names and partial expressions unknown", () => {
const result = run(
[
{ value: "/a/%2e%2e/admin" },
{ value: "GetViewer" },
{ value: "trpc.user.byId" },
{ value: "fetch(prefix + path)", resolution: "partial" },
],
[{ path: "/admin" }],
);
if (!result.ok) throw result.error;
expect(result.value.summary.unknown).toBe(4);
expect(result.value.matches).toEqual([]);
});
it.each([false, true])(
"keeps ambiguity on both sides and preserves confirmed method matches (known peer: %s)",
(knownPeer) => {
const result = run(
[
{ value: "/ambiguous" },
...(knownPeer
? [{ value: "/ambiguous", mechanism: "new:EventSource" }]
: []),
{ value: "/events", mechanism: "new:EventSource" },
],
[
{ path: "/ambiguous", method: "GET" },
{ path: "/ambiguous", method: "POST" },
{ path: "/events", method: "POST" },
],
);
if (!result.ok) throw result.error;
expect(
result.value.static_endpoints.find(
({ path, method }) => path === "/ambiguous" && method === null,
),
).toMatchObject({
status: "unknown",
reason: "ambiguous-method",
method: null,
});
expect(
result.value.static_endpoints.find(({ path }) => path === "/events"),
).toMatchObject({ status: "not-observed-in-capture", method: "GET" });
expect(result.value.summary.observed_unknown).toBe(knownPeer ? 1 : 2);
expect(
result.value.observed_groups.find(
({ path_template, method }) =>
path_template === "/ambiguous" && method === "POST",
),
).toMatchObject({ status: "unknown", reason: "ambiguous-static-method" });
expect(
result.value.observed_groups.find(
({ path_template, method }) =>
path_template === "/ambiguous" && method === "GET",
),
).toMatchObject({
status: knownPeer ? "matched" : "unknown",
reason: knownPeer ? null : "ambiguous-static-method",
});
},
);
it("does not upgrade absence when even one recorded request is excluded", () => {
const result = run(
[{ value: "/missing" }],
[{ path: "/known" }, { path: "/omitted", method: "" }],
);
if (!result.ok) throw result.error;
expect(result.value.static_endpoints[0]).toMatchObject({
status: "unknown",
reason: "capture-incomplete",
});
});
it("charges comparison state against the inherited representation allowance", () => {
const result = run([{ value: "/large".repeat(500) }], [{ path: "/known" }], {
budget: 4096,
});
expect(result).toMatchObject({
ok: false,
error: { _tag: "AnalysisResourceConstraintError" },
});
});