fix(analysis): validate native UI seed addresses

This commit is contained in:
morluto committed 2026-10-27 13:42:33 +08:00
1 parent c9df40f810
commit 2733979b4d
2 files changed
+36 -6

No files matched your search

@@ -308,6 +308,9 @@ describe("native UI action trace", () => {
}),
);
});
});
describe("native UI action seed resolution", () => {
it("accepts an explicit native seed without an authored UI connection", async () => {
const result = await new EnhancedTools(
testAnalysis({
@@ -324,6 +327,31 @@ describe("native UI action trace", () => {
},
});
});
it.each(["", null, 0, { address: "0x1000" }])(
"rejects a malformed provider canonical seed address: %j",
async (address) => {
let traversed = false;
const result = await new EnhancedTools(
testAnalysis({
procedure_address: () => execution("procedure_address", address),
procedure_callees: () => {
traversed = true;
return execution("procedure_callees", []);
},
}),
).execute("trace_native_ui_action", { action: "missing-selector" });
expect(result).toMatchObject({
ok: false,
error: {
_tag: "AnalysisOutputError",
operation: "procedure_address",
reason: "provider returned no canonical procedure address",
},
});
expect(traversed).toBe(false);
},
);
it("builds the evidence path from provider names with declared symbol facts", async () => {
const tools = new EnhancedTools(
testAnalysis({
@@ -14,6 +14,7 @@ import {
} from "../../domain/native/nativeInvestigationGraph.js";
import { nativeDispatchMetadataResultSchema } from "../../domain/native/objcSwiftMetadata.js";
import { inspectNativeDispatch } from "./NativeDispatchMetadataInspection.js";
import { parseProcedureAddress } from "../ProcedureAddressResolution.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import { readNativeCallRoutes } from "./NativeCallRoutes.js";
import {
@@ -163,26 +164,27 @@ export const traceNativeUiAction = async (
if (!native.ok && !permitsCapabilityFallback(native.error))
return err(native.error);
if (native.ok) {
const address = z.string().safeParse(native.value.result);
if (!address.success || native.value.subject?.sha256 !== targetSha256)
const address = parseProcedureAddress(native.value.result);
if (!address.ok) return address;
if (native.value.subject?.sha256 !== targetSha256)
return err(
new AnalysisOutputError(
NATIVE_UI_ACTION_OPERATIONS.nativeSeed,
"Native seed lacks a validated address or matching target identity",
"Native seed lacks matching target identity",
),
);
const id = `native:function:${address.data}`;
const id = `native:function:${address.value}`;
graph.nodes.push({
id,
kind: "function",
name: input.action,
location: { address: address.data, file_offset: null },
location: { address: address.value, file_offset: null },
attributes: { resolved_by: native.value.provider.id },
evidence: [
{
kind: "reference",
description: `Provider resolved the explicit native seed ${input.action}`,
location: { address: address.data, file_offset: null },
location: { address: address.value, file_offset: null },
artifact_path: null,
artifact_sha256: targetSha256,
},