fix(managed): share native verification input diagnostics (#2901)

This commit is contained in:
ShitK 2026-10-14 00:33:14 +08:00 committed by GitHub
parent df3d96da80
commit 501c5d45fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 86 additions and 43 deletions

View File

@ -1,5 +1,6 @@
import { z } from "zod";
import { evidenceSchema } from "../../domain/evidence.js";
import { managedNativeVerificationInputSchema } from "../../domain/managed/managedNativeVerificationSchemas.js";
import { managedReconstructionImportInputSchema } from "../../domain/managed/managedReconstruction.js";
import type { ToolContract } from "../toolContractTypes.js";
@ -34,35 +35,6 @@ export const managedReconstructionReferenceInputSchema =
static_members: evidenceSchema,
});
/** Inline Evidence inputs for managed/native verification. */
export const managedNativeVerificationReferenceInputSchema = z
.strictObject({
managed_boundaries: evidenceSchema,
native_observations: z
.array(evidenceSchema)
.min(1)
.describe("Native function or export Evidence records"),
})
.superRefine((input, context) => {
const ids = new Set<string>([input.managed_boundaries.evidence_id]);
for (const [index, evidence] of input.native_observations.entries()) {
if (evidence.evidence_id === input.managed_boundaries.evidence_id)
context.addIssue({
code: "custom",
path: ["native_observations", index],
message:
"Native observation Evidence must be distinct from managed boundary Evidence",
});
if (ids.has(evidence.evidence_id))
context.addIssue({
code: "custom",
path: ["native_observations", index],
message: "Native observation Evidence IDs must be unique",
});
ids.add(evidence.evidence_id);
}
});
const managedApplicationGraphReferenceFacts = {} as const;
const managedApplicationGraphReferenceShape = z.strictObject({
@ -146,7 +118,7 @@ export const MANAGED_WORKFLOW_TOOL_CONTRACTS = [
description:
"Verify managed P/Invoke/native-boundary declarations against authenticated native export or function Evidence without executing managed code or translating managed metadata tokens into native addresses. The workflow preserves declaration-only, verified, inferred, contradicted, and unresolved states.",
kind: "application",
inputSchema: managedNativeVerificationReferenceInputSchema,
inputSchema: managedNativeVerificationInputSchema,
outputSchema: nativeVerificationOutputSchema,
examples: [
{

View File

@ -1,5 +1,9 @@
import { describe, expect, it } from "vitest";
import { managedNativeVerificationInputSchema } from "../domain/managed/managedNativeVerificationSchemas.js";
import { toolContract } from "./toolContracts.js";
import { toolInputSchemaWithMetadata } from "./toolSchemaMetadata.js";
import { traceJavaScriptSemanticsRequestSchema } from "./javascript/applicationWorkflowInputContracts.js";
import { JAVASCRIPT_FEATURE_TRACE_EXAMPLE } from "./javascript/javascriptApplicationWorkflowExamples.js";
import {
@ -10,7 +14,6 @@ import {
import {
compareManagedMembersReferenceInputSchema,
managedApplicationGraphReferenceInputSchema,
managedNativeVerificationReferenceInputSchema,
} from "./managed/managedWorkflowToolContracts.js";
describe("workflow input contracts", () => {
@ -41,17 +44,6 @@ describe("workflow input contracts", () => {
}).success,
).toBe(false);
expect(
managedNativeVerificationReferenceInputSchema.safeParse({
managed_boundaries:
MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries,
native_observations: [
MANAGED_NATIVE_VERIFICATION_EXAMPLE.native_observations[0],
MANAGED_NATIVE_VERIFICATION_EXAMPLE.native_observations[0],
],
}).success,
).toBe(false);
expect(
managedApplicationGraphReferenceInputSchema.safeParse({
managed_artifact: MANAGED_APPLICATION_GRAPH_EXAMPLE.managed_members,
@ -62,4 +54,80 @@ describe("workflow input contracts", () => {
managedApplicationGraphReferenceInputSchema.safeParse({}).success,
).toBe(false);
});
it.each([
{
name: "one observation reusing the boundary",
observations: [MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries],
issues: [
{
path: ["native_observations", 0],
message:
"Native observation Evidence must be distinct from managed boundary Evidence",
},
],
},
{
name: "repeated native observations",
observations: [
MANAGED_NATIVE_VERIFICATION_EXAMPLE.native_observations[0],
MANAGED_NATIVE_VERIFICATION_EXAMPLE.native_observations[0],
],
issues: [
{
path: ["native_observations", 1],
message: "Native observation Evidence IDs must be unique",
},
],
},
{
name: "repeated observations reusing the boundary",
observations: [
MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries,
MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries,
],
issues: [
{
path: ["native_observations", 0],
message:
"Native observation Evidence must be distinct from managed boundary Evidence",
},
{
path: ["native_observations", 1],
message:
"Native observation Evidence must be distinct from managed boundary Evidence",
},
{
path: ["native_observations", 1],
message: "Native observation Evidence IDs must be unique",
},
],
},
{
name: "distinct native observations",
observations: MANAGED_NATIVE_VERIFICATION_EXAMPLE.native_observations,
issues: [],
},
])(
"preserves managed/native diagnostics for $name",
async ({ observations, issues }) => {
const input = {
managed_boundaries:
MANAGED_NATIVE_VERIFICATION_EXAMPLE.managed_boundaries,
native_observations: observations,
};
const contract = toolContract("verify_managed_native_boundaries");
for (const schema of [
managedNativeVerificationInputSchema,
contract.inputSchema,
toolInputSchemaWithMetadata(contract),
]) {
const result = await schema["~standard"].validate(input);
expect(
result.issues?.map(({ path, message }) => ({ path, message })) ?? [],
).toEqual(issues);
if (issues.length === 0) expect(result).toEqual({ value: input });
}
},
);
});

View File

@ -92,7 +92,10 @@ export type PinvokeVerification = z.infer<typeof pinvokeVerificationSchema>;
export const managedNativeVerificationInputSchema = z
.strictObject({
managed_boundaries: evidenceSchema,
native_observations: z.array(evidenceSchema).min(1),
native_observations: z
.array(evidenceSchema)
.min(1)
.describe("Native function or export Evidence records"),
})
.superRefine((input, context) => {
const ids = new Set<string>();