Files
rea/src/contracts/native/nativeToolContracts.ts
T
MasonGitHubDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com>morluto
5eb296649d fix(native): refuse inspect_signature on non-Mach-O targets (#2262)
* fix(native): refuse inspect_signature on non-Mach-O targets

This provider's signature inspection covers Mach-O code signatures only.
On a xar pkg, codesign's "code object is not signed" verdict cannot see
the archive-level signature layer, so a signed or invalidly-signed package
was reported as signed:false with "Artifact is not signed." Match the
existing inspect_macho/list_architectures gate and report
capability_unavailable instead of an unsigned claim for a layer that was
never evaluated.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(native): scope the signature-gate comment to this provider

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(native): align signature capability discovery with Mach-O support

Bind inspect_signature availability to Mach-O targets in capability discovery and align the public tool description.

Source inspection and git diff --check; tests/builds/typechecks/CI reruns skipped at explicit user request.

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: morluto <76467478+morluto@users.noreply.github.com>
2026-10-13 21:22:42 +08:00

135 lines
5.8 KiB
TypeScript

import { z } from "zod";
import { nativeCallObservationInputSchema } from "../../domain/native/nativeCallObservation.js";
import {
nativeUiObservationInputSchema,
nativeUiScenarioInputSchema,
} from "../../domain/native/nativeUiObservation.js";
import type { ToolContract } from "../toolContractTypes.js";
import { nativeOutputSchemas } from "../toolOutputSchemaGroups.js";
import { jsonValueSchema } from "../../domain/jsonValue.js";
import { localPathStringSchema } from "../../domain/localPath.js";
import { toolContractMetadata } from "../toolEffects.js";
import { requireOutputSchema } from "../toolOutputSchemaPrimitives.js";
import { analysisDetailSchema } from "../analysisDetail.js";
const examples: Readonly<Record<string, Readonly<Record<string, unknown>>>> = {
inspect_macho: {},
inspect_signature: {},
inspect_plist: { path: "/Applications/Example.app/Contents/Info.plist" },
list_architectures: {},
observe_native_ui: { pid: 123, window_id: 456 },
capture_native_ui_scenario: {
pid: 123,
window_id: 456,
steps: [{ kind: "wait", milliseconds: 100 }],
},
demangle_swift: { symbols: ["$s4Test3fooyyF"] },
observe_native_calls: {
breakpoints: [
{
kind: "objc-method",
class_name: "NSURLSession",
selector: "dataTaskWithRequest:completionHandler:",
},
{ kind: "function", name: "open", module: "libsystem_kernel.dylib" },
],
arguments: ["--help"],
duration_ms: 5000,
backtrace_frames: 4,
},
};
const native = <Name extends string, Schema extends z.ZodObject>(
name: Name,
description: string,
inputSchema: Schema,
) => {
const outputSchema = requireOutputSchema(nativeOutputSchemas, name);
const strictInputSchema = inputSchema.strict();
return {
name,
...toolContractMetadata(name),
description,
kind: "native-provider",
inputSchema: strictInputSchema,
outputSchema,
examples: [
{
title: `Example ${name.replaceAll("_", " ")} request`,
input: z
.record(z.string(), jsonValueSchema)
.parse(examples[name] ?? {}),
},
],
} satisfies ToolContract<Name, typeof strictInputSchema, typeof outputSchema>;
};
/** Ordered single-line symbols; `swift-demangle` ends each result with LF. */
export const swiftSymbolsSchema = z
.array(
z
.string()
.min(1)
.regex(/^[^\n]*$/u, "Each Swift symbol must be one line.")
.regex(/^[^\x00]*$/u, "Swift symbols cannot contain NUL."),
)
.min(1);
/** Provider-neutral semantic operations backed initially by macOS utilities. */
export const NATIVE_TOOL_CONTRACTS = [
native(
"observe_native_ui",
"Observe an already-running native app by PID and window ID, bound to the active Mach-O target. Captures a bounded accessibility tree and selected-window screenshot; OS permission denial fails without broad capture or target launch.",
nativeUiObservationInputSchema,
),
native(
"capture_native_ui_scenario",
"Run selected-element press, increment/decrement scroll, AXValue text entry and bounded wait steps in one exact native app window. Returns ordered before/after captures and action/capture failures. Actions can change app data, network activity and persistent state; application state is left as-is and restoration is not attempted.",
nativeUiScenarioInputSchema,
),
native(
"observe_native_calls",
"Launch the active Mach-O as an owned process under LLDB and record each entry into caller-selected functions or Objective-C methods: thread, module, symbol, load and file address, raw argument registers, selector, receiver class and optional caller frames. Every hit auto-continues. No expression is evaluated and no other process is attached. The process is killed when max_events or duration_ms is reached; exit status, captured stdout/stderr, unresolved breakpoints and limitations are returned inline. The process runs with the current user's permissions and may change files, show UI or use the network. A hardened-runtime target needs the get-task-allow entitlement.",
nativeCallObservationInputSchema,
),
native(
"inspect_macho",
"Inspect Mach-O slices, load commands, imports, exports, dependencies, build metadata, segments, sections, permissions, and exact command provenance without launching Hopper. Large frameworks return megabytes of symbols; detail summary retains the complete Evidence and returns slice identity with per-collection counts, then page rows with inspect_analysis_view kind macho.",
z.object({
detail: analysisDetailSchema
.unwrap()
.optional()
.describe(
"Omitted or complete returns the complete inspection Evidence. summary retains that complete Evidence in this session and returns its inspect_analysis_view summary; use normalized_result.parent_evidence_id for macho pages.",
),
}),
),
native(
"inspect_signature",
"Inspect the active Mach-O executable's code-signing identity, hashes, authorities, requirements, entitlements, hardened-runtime state, and exact command provenance.",
z.object({}),
),
native(
"inspect_plist",
"Parse Info.plist from the active artifact by default, or pass any local plist path. Returns normalized JSON rather than plutil text.",
z.object({
path: localPathStringSchema.optional(),
}),
),
native(
"list_architectures",
"List thin or universal Mach-O slices with offsets, sizes, alignment, explicit coverage, and native-tool provenance.",
z.object({}),
),
native(
"demangle_swift",
"Demangle an ordered list of single-line Swift symbols without requiring Hopper. Each input returns demangled, unchanged, or invalid status.",
z.object({
symbols: swiftSymbolsSchema,
}),
),
] as const satisfies readonly ToolContract[];
export type NativeToolName = (typeof NATIVE_TOOL_CONTRACTS)[number]["name"];