fix(verifiers): read packed bridge without extraction

Parse only the exact regular packed Python bridge member without extracting into the caller-owned private runtime root. Preserve required Ghidra admission, typed callers, native lease ownership and cleanup on success or failure.

Validation: 263 focused real tar/Python/ownership and CI selection checks, 42 official WABT packaged CLI/MCP cases, full check:ci/check:fast/actionlint, real-package alternating measurements and exact-head hosted CI passed. The required Windows lane exercises the retained native lease without skipping missing authority.

Fixes #4134.

Co-authored-by: abdooo2235 <abdalrhmantheiv15@gmail.com>
This commit is contained in:
Ysopwnable
2026-10-17 18:35:31 +08:00
committed by GitHub
parent 73965f9431
commit f0d175dace
9 changed files with 216 additions and 9 deletions
+2
View File
@@ -118,6 +118,7 @@ export const SCOPES = {
"scripts/verify/inspector/**",
"scripts/verify-package.mjs",
"scripts/verify-package-*",
"scripts/verify-packed-bridge.*",
"scripts/verify-windows-*.mjs",
"scripts/build-windows-native.mjs",
"scripts/windows-capabilities.mjs",
@@ -145,6 +146,7 @@ export const SCOPES = {
"tests/boundary/filesystem/webScriptManifestPaths.test.ts",
"tests/boundary/process/ProcessEvidence.host.test.ts",
"tests/boundary/process/packageNpmInvocation.test.ts",
"tests/boundary/process/packedBridgeVerification.test.ts",
"tests/boundary/process/windowsOutputCapture.test.ts",
"tests/acceptance/webModuleCli.test.ts",
"tests/acceptance/webSourceLocationCli.test.ts",
+1 -1
View File
@@ -66,6 +66,6 @@ export async function verifyPackagePack({ root, workspace }) {
) {
throw new Error("package contained generated Python bytecode");
}
await verifyPackedBridge({ workspace, tarball, packedFiles });
await verifyPackedBridge({ tarball, packedFiles });
return { tarball };
}
+5
View File
@@ -0,0 +1,5 @@
/** Validate required shipped bridges and parse packed Python without extraction. */
export function verifyPackedBridge(input: {
readonly tarball: string;
readonly packedFiles: readonly string[];
}): Promise<void>;
+13 -7
View File
@@ -1,5 +1,4 @@
import { execFile } from "node:child_process";
import { join } from "node:path";
import { promisify } from "node:util";
import { GHIDRA_BRIDGE_SOURCES } from "../src/ghidra/GhidraBridgeSources.ts";
@@ -8,7 +7,7 @@ const packedHopperBridge = "package/bridge/hopper_bridge.py";
const packedCutterBridge = "package/bridge/cutter/rea_bridge.py";
/** Check shipped bridge files; real-provider lanes verify runtime behavior. */
export async function verifyPackedBridge({ workspace, tarball, packedFiles }) {
export async function verifyPackedBridge({ tarball, packedFiles }) {
for (const path of [
packedHopperBridge,
packedCutterBridge,
@@ -18,12 +17,19 @@ export async function verifyPackedBridge({ workspace, tarball, packedFiles }) {
]) {
if (!packedFiles.includes(path)) throw new Error(`package omitted ${path}`);
}
await exec("tar", ["-xf", tarball, "-C", workspace]);
// Parse the actual packed Python source without loading Hopper globals or
// generating bytecode. This check has no dependency on test-only fixtures.
// Read the packed source without extracting into the caller's leased root.
await exec("python3", [
"-c",
"import ast, pathlib, sys; p = pathlib.Path(sys.argv[1]); ast.parse(p.read_text(encoding='utf-8'), filename=str(p))",
join(workspace, packedHopperBridge),
[
"import ast, sys, tarfile",
"with tarfile.open(sys.argv[1]) as archive:",
" member = archive.getmember(sys.argv[2])",
" if not member.isfile():",
" raise ValueError(f'{member.name} is not a regular file')",
" with archive.extractfile(member) as source:",
" ast.parse(source.read().decode('utf-8'), filename=sys.argv[2])",
].join("\n"),
tarball,
packedHopperBridge,
]);
}