fix(package-verifier): reject overview responses without a procedure count (#2936)

* fix(package-verifier): reject overview responses without a procedure count

The analyze and inspect checks compared procedure_count with `< 1`, and an absent
or null normalized_result makes that comparison false, so a binary_overview
response without its required result passed the platform smoke check. Require an
integer procedure count before the positive-count comparison.

* test(package-verifier): cover malformed overview receipts

---------

Co-authored-by: REA Maintenance <76467478+morluto@users.noreply.github.com>
This commit is contained in:
CodeAlex
2026-10-14 03:06:53 +08:00
committed by GitHub
parent 64041e3072
commit 4758ba30b6
3 changed files with 96 additions and 16 deletions
+6
View File
@@ -8,4 +8,10 @@ export function assertLinuxPackageProviderFailure(execution: {
export function verifyPackagePlatform(input: {
readonly cli: string;
readonly environment: Readonly<Record<string, string | undefined>>;
readonly platform?: string;
readonly runCommand?: (
command: string,
arguments_: readonly string[],
environment: Readonly<Record<string, string | undefined>>,
) => Promise<string>;
}): Promise<void>;
+29 -15
View File
@@ -1,8 +1,13 @@
import { json, run, runWithStatus } from "./lib/verify-package-core.mjs";
/** Run platform-specific deep-analysis smoke tests. */
export async function verifyPackagePlatform({ cli, environment }) {
if (process.platform === "linux") {
export async function verifyPackagePlatform({
cli,
environment,
platform = process.platform,
runCommand = run,
}) {
if (platform === "linux") {
const unsupportedExecution = await runWithStatus(
cli,
["analyze", process.execPath, "--json"],
@@ -11,25 +16,27 @@ export async function verifyPackagePlatform({ cli, environment }) {
assertLinuxPackageProviderFailure(unsupportedExecution);
} else {
const overview = json(
await run(cli, ["analyze", process.execPath, "--json"], environment),
await runCommand(
cli,
["analyze", process.execPath, "--json"],
environment,
),
);
if (
overview.operation !== "binary_overview" ||
overview.normalized_result?.procedure_count < 1
)
if (!hasPositiveProcedureCount(overview))
throw new Error(
`packaged Hopper-backed analyze CLI failed: ${JSON.stringify(overview)}`,
);
const inspected = json(
await run(cli, ["inspect", process.execPath, "--json"], environment),
await runCommand(
cli,
["inspect", process.execPath, "--json"],
environment,
),
);
if (
inspected.operation !== "binary_overview" ||
inspected.normalized_result?.procedure_count < 1
)
if (!hasPositiveProcedureCount(inspected))
throw new Error("packaged inspect CLI failed");
const functionResult = json(
await run(
await runCommand(
cli,
["function", process.execPath, "0x1000", "--json"],
environment,
@@ -44,7 +51,7 @@ export async function verifyPackagePlatform({ cli, environment }) {
`packaged function CLI failed: ${JSON.stringify(functionResult)}`,
);
const xrefs = json(
await run(
await runCommand(
cli,
["xrefs", process.execPath, "0x1000", "--json"],
environment,
@@ -56,7 +63,7 @@ export async function verifyPackagePlatform({ cli, environment }) {
)
throw new Error(`packaged xrefs CLI failed: ${JSON.stringify(xrefs)}`);
const trace = json(
await run(
await runCommand(
cli,
["trace", process.execPath, "fixture", "--json"],
environment,
@@ -93,3 +100,10 @@ export const assertLinuxPackageProviderFailure = (execution) => {
`packaged Linux Hopper verification did not fail closed: ${JSON.stringify(failure)}`,
);
};
const hasPositiveProcedureCount = (result) =>
typeof result === "object" &&
result !== null &&
result.operation === "binary_overview" &&
Number.isInteger(result.normalized_result?.procedure_count) &&
result.normalized_result.procedure_count > 0;
@@ -1,6 +1,9 @@
import { describe, expect, it } from "vitest";
import { assertLinuxPackageProviderFailure } from "../../../scripts/verify-package-platform.mjs";
import {
assertLinuxPackageProviderFailure,
verifyPackagePlatform,
} from "../../../scripts/verify-package-platform.mjs";
const missingDisplay = {
code: "provider_unavailable",
@@ -22,6 +25,37 @@ const execution = (failure: unknown, status = 1) => ({
stdout: JSON.stringify(failure),
});
const overview = (procedure_count?: unknown, operation = "binary_overview") => ({
operation,
...(procedure_count === undefined
? {}
: { normalized_result: { procedure_count } }),
});
const verifyMacOS = async (
analyze: unknown,
inspect: unknown,
): Promise<void> => {
const outputs: Readonly<Record<string, unknown>> = {
analyze,
inspect,
function: {
operation: "analyze_function",
provider: { id: "hopper" },
normalized_result: { procedure: { address: "0x1000" } },
},
xrefs: { operation: "xrefs", normalized_result: ["0x1000"] },
trace: { operation: "trace_feature" },
};
await verifyPackagePlatform({
cli: "fixture-cli",
environment: {},
platform: "darwin",
runCommand: async (_cli, arguments_) =>
JSON.stringify(outputs[arguments_[0]!]) ?? "",
});
};
describe("packaged Linux failure verification", () => {
it("accepts the unsupported fixture build or an exact missing display dependency", () => {
expect(() =>
@@ -71,3 +105,29 @@ describe("packaged Linux failure verification", () => {
},
);
});
describe("packaged analyze and inspect result guards", () => {
it("accepts positive integer procedure counts for both commands", async () => {
await verifyMacOS(overview(1), overview(2));
});
const malformed = [
["missing result", undefined],
["null result", null],
["missing normalized count", overview()],
["zero count", overview(0)],
["non-integer count", overview(1.5)],
["wrong operation", overview(2, "other_operation")],
] as const;
it.each(["analyze", "inspect"] as const)(
"rejects malformed %s results before trusting the package",
async (command) => {
for (const [label, invalid] of malformed) {
const analyze = command === "analyze" ? invalid : overview(4);
const inspect = command === "inspect" ? invalid : overview(4);
await expect(verifyMacOS(analyze, inspect), label).rejects.toThrow();
}
},
);
});