mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 19:23:24 +00:00
* feat(evidence)!: give Evidence bundles a format revision owned by one module `src/domain/evidenceFormat.ts` owns Evidence format evolution. Bundles now carry `evidence_format: 1`; every bundle reader admits only the current revision and refuses an unmarked or other-revision bundle once, with the single recreate-observations guidance, instead of admitting earlier shapes one optional field at a time. The 6.7-era artifact inventory summary identities are no longer rebuilt: compare_artifacts checks the current projection only and reports a mismatch with the owner's guidance. The pre-6.6 identity diagnosis uses the same guidance. SQLite `worker_timeout_ms` and Dart AOT `string_pool.policy`, optional only for historical Evidence, are now required. BREAKING CHANGE: Evidence bundles written by REA 6.x (no `evidence_format`) are refused by import, comparison, reconstruction and analysis-snapshot readers as an integrity mismatch telling the caller to recreate the observations; re-exporting an earlier bundle does not update its format or identities. Bundles constructed by hand must include `"evidence_format": 1`. 6.7-era artifact summaries are refused by compare_artifacts, and SQLite and Dart AOT Evidence without the newly required fields fails validation. * fix(evidence): let the ledger application admit its bundle's format build_reconstruction_obligation_ledger registered the full bundle schema with the SDK, so an unmarked or other-revision bundle was refused as invalid_request before the format owner ran. Register it like coverage: the application parses the request envelope and admits the bundle. * feat(pcap)!: read capture Evidence through the current result schema only (#10879) Delete the pcap read-compatibility schema that defaulted executable identity for historical capture Evidence, and require query_labels_hex (null when unknown) now that every producer writes it. Evidence from an earlier format is refused at the bundle format owner; a record that omits these fields is reported as malformed instead of defaulted. BREAKING CHANGE: inspect_pcap_capture results always carry query_labels_hex, and analysis views no longer default missing tshark/capinfos identity fields. * feat(desktop)!: require the effective view policy in desktop state Evidence (#10886) inspect_desktop_application_state always records the complete policy it used, including sqlite_view_bytes. Drop the optional historical shape and the task draft's absent-policy branch. BREAKING CHANGE: desktop application state results without effective_view_policy, or with a policy missing sqlite_view_bytes, are refused as malformed. * feat(android)!: require component declaration facets and reference aggregates in Android Evidence (#10904) * feat(android)!: require component declaration facets and reference aggregates in Android Evidence The JADX producers always write the manifest component projection with every declaration facet, target_definition and direct_invokes_coverage. Require them, delete the duplicate observed component schema, drop the unknown declaration coverage that only described historical omission, and give manifest view results their explicit facet. BREAKING CHANGE: Android package, component and reference results missing these fields are refused as malformed; component declaration_coverage and its summary counts no longer include unknown; manifest view results always carry facet manifest. * refactor(android): parse package results with the domain schema directly * feat(browser)!: require the DOM length unit and redirect-scoped prior-hop facts (#10897) * feat(browser)!: require the DOM length unit and redirect-scoped prior-hop facts Both CDP producers always declare node_value_length_unit, and the observation session writes redirect_response on every redirect event and no other. Require the unit, drop the diff's absent-unit branch, and admit redirect_response exactly on redirect rows. BREAKING CHANGE: DOM snapshots without node_value_length_unit and redirect timeline rows without redirect_response are refused as malformed, including inline inspections passed to compare_web_captures. * docs(browser): drop the historical redirect_response omission note * feat(native)!: require native Evidence fields that were optional only for historical Evidence (#10946) Mach-O encryption, slice malformed cause, symbol runtime names and import facts; ELF export encoding facts and visibility; value-flow limits; load-image permissions and relocation symbols; Swift type-reference kind and GPU AMD target metadata are required. Legacy enum values (unrecorded, unknown visibility, undecodable, modinfo_field_exceeds_limit) and the retained schemas, view defaults and reinterpretations that served historical Evidence are deleted. BREAKING CHANGE: native records missing these fields are refused as malformed; recreate the observation.
117 lines
3.9 KiB
TypeScript
117 lines
3.9 KiB
TypeScript
import { expect, onTestFinished } from "vitest";
|
|
import { z } from "zod";
|
|
import { toolContract } from "../../src/contracts/toolContracts.js";
|
|
import { webObservationSessionSchema } from "../../src/domain/browserSession.js";
|
|
import { startFakeCdpBrowser } from "../fixtures/fakeCdpBrowser.js";
|
|
import { connectLocalToolsMcp } from "../fixtures/localToolsMcp.js";
|
|
import { cliTest } from "../support/cli/cliFixture.js";
|
|
|
|
cliTest.for(["CLI", "stdio MCP"] as const)(
|
|
"retains admitted redirect response facts exactly on redirect events through %s",
|
|
async (surface, { cli }) => {
|
|
const browser = await startFakeCdpBrowser({
|
|
eventsBeforeReply: ["Page.setLifecycleEventsEnabled"],
|
|
commandResult: (command) =>
|
|
command.method === "Performance.getMetrics"
|
|
? { metrics: [{ name: "Timestamp", value: 20 }] }
|
|
: undefined,
|
|
commandEvents: (command, origin) =>
|
|
command.method === "Page.setLifecycleEventsEnabled"
|
|
? [
|
|
{
|
|
method: "Network.requestWillBeSent",
|
|
sessionId: command.sessionId,
|
|
params: {
|
|
requestId: "redirect-chain",
|
|
frameId: "frame-main",
|
|
type: "Document",
|
|
timestamp: 21,
|
|
request: { url: `${origin}/after`, method: "GET" },
|
|
redirectResponse: {
|
|
url: `${origin}/before?token=visible`,
|
|
status: 302,
|
|
headers: { Authorization: "discard-redirect-header" },
|
|
body: "discard-redirect-body",
|
|
},
|
|
},
|
|
},
|
|
]
|
|
: undefined,
|
|
});
|
|
onTestFinished(() => browser.close());
|
|
let evidence: unknown;
|
|
if (surface === "CLI") {
|
|
const reply = await cli.run({
|
|
arguments: [
|
|
"observe-web-session",
|
|
browser.endpoint,
|
|
"allowed-page",
|
|
"--allowed-origins",
|
|
browser.allowedOrigin,
|
|
"--observation-ms",
|
|
"5",
|
|
"--json",
|
|
],
|
|
});
|
|
expect(reply.exitCode, reply.stderr).toBe(0);
|
|
evidence = reply.json;
|
|
} else {
|
|
const { call } = await connectLocalToolsMcp();
|
|
const reply = await call("observe_web_session", {
|
|
cdp_endpoint: browser.endpoint,
|
|
allowed_origins: [browser.allowedOrigin],
|
|
target_id: "allowed-page",
|
|
observation_ms: 5,
|
|
});
|
|
expect(reply.isError, JSON.stringify(reply.content)).not.toBe(true);
|
|
evidence = reply.structuredContent;
|
|
}
|
|
const source = toolContract("observe_web_session").outputSchema.parse(
|
|
evidence,
|
|
);
|
|
const result = z
|
|
.object({ normalized_result: webObservationSessionSchema })
|
|
.parse(source).normalized_result;
|
|
expect(result.timeline).toContainEqual(
|
|
expect.objectContaining({
|
|
type: "redirect",
|
|
request_id: "redirect-chain",
|
|
timestamp: 21,
|
|
url: `${browser.allowedOrigin}/after`,
|
|
redirect_response: {
|
|
url: `${browser.allowedOrigin}/before?token=visible`,
|
|
status: 302,
|
|
scope: "approved",
|
|
},
|
|
}),
|
|
);
|
|
expect(JSON.stringify(source)).not.toContain("discard-redirect-");
|
|
const omitted = {
|
|
...result,
|
|
timeline: result.timeline.map(({ redirect_response, ...row }) => {
|
|
void redirect_response;
|
|
return row;
|
|
}),
|
|
};
|
|
const misplaced = {
|
|
...result,
|
|
timeline: result.timeline.map((row) => ({
|
|
...row,
|
|
type: "lifecycle" as const,
|
|
})),
|
|
};
|
|
for (const malformed of [omitted, misplaced])
|
|
expect(webObservationSessionSchema.safeParse(malformed)).toMatchObject({
|
|
success: false,
|
|
error: {
|
|
issues: expect.arrayContaining([
|
|
expect.objectContaining({
|
|
message:
|
|
"redirect_response is present exactly on redirect events.",
|
|
}),
|
|
]),
|
|
},
|
|
});
|
|
},
|
|
);
|