fix(managed): report a managed graph over an unavailable source as unknown (#11280)

This commit is contained in:
morluto authored and GitHub committed 2026-11-15 10:34:17 -05:00
1 parent ac9064b394
commit c931ba43ab
6 files changed
+128 -34

No files matched your search

@@ -724,6 +724,11 @@ type selection. Limitations name each counted class, and graph coverage is
incomplete. A missing `calls` edge is therefore not evidence that a method is
never called.
A supplied inspection whose parser coverage is `unavailable` examined nothing,
so the graph cannot tell what it omits: the result's `coverage.status` and the
graph coverage are then `unknown`, even beside a known gap in another source.
`partial` is reserved for known gaps.
## Evidence record shape
Member comparison, application graph projection, and managed/native verification
@@ -458,7 +458,7 @@
"src/domain/javascript/sourceToBundleComparisonSchemas.ts": 1,
"src/domain/javascript/staticObservedEndpointSchemas.ts": 1,
"src/domain/jeb/jebAnalysis.ts": 1,
"src/domain/managed/managedArtifact.ts": 6,
"src/domain/managed/managedArtifact.ts": 4,
"src/domain/managed/managedMemberComparison.ts": 3,
"src/domain/managed/managedNativeVerificationSchemas.ts": 2,
"src/domain/managed/managedReconstruction.ts": 1,
+11 -2
View File
@@ -118,7 +118,11 @@ export const managedApplicationGraphResultSchema = z
}),
graph: javascriptApplicationGraphSchema,
coverage: z.strictObject({
status: z.enum(["complete-within-inputs", "partial"]),
status: z
.enum(["complete-within-inputs", "partial", "unknown"])
.describe(
"complete-within-inputs when every supplied managed Evidence record is complete and nothing was omitted; unknown when a supplied record is unavailable.",
),
}),
evidence_links: z.array(evidenceIdSchema).min(1).max(3),
limitations: z.array(nonEmptyTextSchema),
@@ -428,9 +432,14 @@ const projectionLimitations = (
"Managed native-boundary Evidence was not supplied; P/Invoke and native-implementation nodes are absent.",
]
: []),
...(omissions.partialInput
...(omissions.inputStates.includes("partial")
? ["At least one supplied managed Evidence record has partial coverage."]
: []),
...(omissions.inputStates.includes("unavailable")
? [
"At least one supplied managed Evidence record is unavailable; what the graph omits is unknown.",
]
: []),
...(omissions.selectedTypes === null
? []
: [
@@ -1,13 +1,14 @@
import { joinCoverageStatus, type CoverageStatus } from "../coverage.js";
import type { ApplicationGraphEvidence } from "../javascript/javascriptApplicationEvidenceSchemas.js";
import type {
ManagedArtifactInspection,
ManagedMemberInspection,
ManagedNativeBoundaryInspection,
import {
managedInspectionCoverage,
type ManagedArtifactInspection,
type ManagedInspectionState,
type ManagedMemberInspection,
type ManagedNativeBoundaryInspection,
} from "./managedArtifact.js";
import { managedTokenScopesMatch } from "./managedInspectionEvidence.js";
type ManagedCoverageState = "complete" | "partial" | "unavailable";
/** Why a call site did not become a `calls` edge. */
export type OmittedCallReason =
| "member-ref"
@@ -44,9 +45,10 @@ export interface ManagedGraphCoverageSources {
readonly boundaries: ManagedNativeBoundaryInspection | null;
}
/** Whether any supplied source has incomplete coverage. */
/** What the supplied sources and the projection left out. */
export interface ManagedGraphProjectionOmissions {
readonly partialInput: boolean;
/** Parser states of the supplied sources; absent sources are not listed. */
readonly inputStates: readonly ManagedInspectionState[];
readonly unscopedTokenRelationships: boolean;
/** Declaring types the member Evidence selected; null when it inspected every type. */
readonly selectedTypes: readonly string[] | null;
@@ -56,9 +58,21 @@ export interface ManagedGraphProjectionOmissions {
readonly relations: ManagedRelationOmissions | null;
}
/**
* Coverage the supplied sources allow: an unavailable source examined nothing,
* so the graph cannot tell what it omits, even beside a known gap.
*/
const inputCoverage = (
omissions: ManagedGraphProjectionOmissions,
): CoverageStatus =>
joinCoverageStatus([
"complete",
...omissions.inputStates.map(managedInspectionCoverage),
]);
/** Omissions whose size is unknown, unlike counted relation sites. */
const omitsUncounted = (omissions: ManagedGraphProjectionOmissions): boolean =>
omissions.partialInput ||
inputCoverage(omissions) !== "complete" ||
omissions.unscopedTokenRelationships ||
omissions.selectedTypes !== null ||
omissions.methodRows !== undefined;
@@ -75,7 +89,7 @@ const completeCoverage = (): ApplicationGraphEvidence["coverage"] => ({
/** Preserve the source parser's coverage state on projected observations. */
export const managedSourceCoverage = (
state: ManagedCoverageState,
state: ManagedInspectionState,
): ApplicationGraphEvidence["coverage"] =>
state === "complete"
? completeCoverage()
@@ -103,11 +117,9 @@ export const assessManagedGraphOmissions = (
sources.members.identity_scope.requires_mvid,
sources.boundaries.identity_scope.requires_mvid,
),
partialInput: [
sources.members?.coverage.state,
sources.boundaries?.coverage.state,
sources.artifact?.coverage.state,
].some((state) => state !== undefined && state !== "complete"),
inputStates: [sources.members, sources.boundaries, sources.artifact].flatMap(
(source) => (source === null ? [] : [source.coverage.state]),
),
selectedTypes: sources.members?.selection?.type_names ?? null,
methodRows:
sources.members === null ||
@@ -122,22 +134,27 @@ export const assessManagedGraphOmissions = (
export const managedGraphEvidenceCoverage = (
omissions: ManagedGraphProjectionOmissions,
): ApplicationGraphEvidence["coverage"] =>
omitsAny(omissions)
? {
status: "partial",
truncated: false,
omitted_count: omitsUncounted(omissions)
? null
: omittedRelationSites(omissions.relations),
limits: [],
}
: completeCoverage();
inputCoverage(omissions) === "unknown"
? { status: "unknown", truncated: false, omitted_count: null, limits: [] }
: omitsAny(omissions)
? {
status: "partial",
truncated: false,
omitted_count: omitsUncounted(omissions)
? null
: omittedRelationSites(omissions.relations),
limits: [],
}
: completeCoverage();
/** Report whether all supplied source evidence was complete. */
export const managedGraphResultCoverage = (
omissions: ManagedGraphProjectionOmissions,
) => ({
status: omitsAny(omissions)
? ("partial" as const)
: ("complete-within-inputs" as const),
status:
inputCoverage(omissions) === "unknown"
? ("unknown" as const)
: omitsAny(omissions)
? ("partial" as const)
: ("complete-within-inputs" as const),
});
+26 -3
View File
@@ -1,4 +1,5 @@
import { z } from "zod";
import type { CoverageStatus } from "../coverage.js";
import { digestSchema } from "../digests.js";
import { managedFieldConstantSchema } from "./managedFieldConstant.js";
@@ -6,6 +7,28 @@ import { managedFieldConstantSchema } from "./managedFieldConstant.js";
export const managedMetadataTokenSchema = z.string().regex(/^0x[0-9a-f]{8}$/u);
const offsetSchema = z.int().min(0);
/**
* Parser coverage of one managed inspection. `unavailable` means the parser
* examined nothing of that kind, unlike `partial`, which records a known gap.
*/
export const managedInspectionStateSchema = z.enum([
"complete",
"partial",
"unavailable",
]);
export type ManagedInspectionState = z.infer<
typeof managedInspectionStateSchema
>;
/**
* What a result derived from one managed inspection can claim about its
* coverage: an unavailable inspection examined nothing, so what it would cover
* is unknown rather than partially known.
*/
export const managedInspectionCoverage = (
state: ManagedInspectionState,
): CoverageStatus => (state === "unavailable" ? "unknown" : state);
/** A 16-byte CLI metadata GUID without RFC 4122 version/variant restrictions. */
export const cliMetadataGuidSchema = z
.string()
@@ -510,7 +533,7 @@ export const managedArtifactInspectionSchema = z.object({
resources: z.array(managedResourceSchema),
attributes: z.array(customAttributeSchema),
coverage: z.object({
state: z.enum(["complete", "partial", "unavailable"]),
state: managedInspectionStateSchema,
issues: z.array(managedParseIssueSchema),
}),
limitations: z.array(z.string()),
@@ -582,7 +605,7 @@ export const managedMemberInspectionSchema = z
"Examined zero-based MethodDef row interval before declaring-type selection; null means the row scope was not recorded. Row coordinates are build-local and cannot prove cross-build member absence for a page.",
),
coverage: z.object({
state: z.enum(["complete", "partial", "unavailable"]),
state: managedInspectionStateSchema,
issues: z.array(managedParseIssueSchema),
}),
limitations: z.array(z.string()),
@@ -629,7 +652,7 @@ export const managedNativeBoundaryInspectionSchema = z.object({
mixed_mode_or_native_header: z.boolean().nullable(),
}),
coverage: z.object({
state: z.enum(["complete", "partial", "unavailable"]),
state: managedInspectionStateSchema,
issues: z.array(managedParseIssueSchema),
}),
limitations: z.array(z.string()),
@@ -921,6 +921,46 @@ describe("managed application graph coverage", () => {
}
}
});
it("reports an unavailable source as unknown, not partial", () => {
const bytes = buildManagedPeFixture();
const binary = managedPeFixtureTarget(bytes, "/fixture/ManagedInterop.exe");
const members = inspectManagedMembersBytes(bytes, binary);
const evidence = (state: "partial" | "unavailable") =>
createEvidence(binary, MANAGED_STATIC_PROVIDER, {
operation: "inspect_managed_members",
parameters: {},
result: { ...members, coverage: { state, issues: [] } },
rawResult: null,
limitations: members.limitations,
});
const project = (state: "partial" | "unavailable") => {
const projection = projectManagedApplicationGraphEvidence({
managed_members: evidence(state),
});
if (!projection.ok) throw new Error("projection failed");
return managedApplicationGraphResultSchema.parse(
parseEvidence(projection.value).normalized_result,
);
};
const unavailable = project("unavailable");
expect(unavailable.coverage).toEqual({ status: "unknown" });
expect(unavailable.graph.coverage).toEqual({
status: "unknown",
truncated: false,
omitted_count: null,
limits: [],
});
expect(unavailable.limitations).toContainEqual(
expect.stringMatching(/managed Evidence record is unavailable/iu),
);
expect(unavailable.limitations).not.toContainEqual(
expect.stringMatching(/partial coverage/iu),
);
// A known gap alone stays partial.
expect(project("partial").coverage).toEqual({ status: "partial" });
});
});
describe("managed application graph type selection", () => {