refactor(python): consolidate bytecode identity across readers

Share CPython magic framing, version and header facts while keeping standalone marshal coverage and PyInstaller reconstruction eligibility distinct. Preserve legacy headers, opaque unknowns and source bytes.

Validated 272 focused tests across source, CLI and MCP workflows, a 38-test reader recheck, and check:fast.
This commit is contained in:
morluto committed 2026-10-27 02:09:52 +08:00
1 parent 669e617eec
commit d06ca092fb
8 files changed
+322 -97

No files matched your search

+54
View File
@@ -139,6 +139,54 @@ it("fails unknown magics and truncated marshal without partial success", () => {
);
});
it.each([
{ magic: 3571, layout: "py311", version: "3.13" },
{ magic: 3401, layout: "py37", version: "3.8" },
] as const)(
"decodes supported standalone magic $magic with its own marshal layout",
({ magic, layout, version }) => {
const result = parse(
Buffer.concat([pythonPycHeader(magic), marshalCode(layout)]),
);
expect(result.header).toMatchObject({
magic,
python_version: version,
code_layout: layout,
});
expect(root(result).name).toBe("<module>");
},
);
it("keeps a known newer CPython identity outside standalone decoder coverage", () => {
expect(() => parse(pythonPycHeader(3627))).toThrow(
expect.objectContaining({
kind: "unsupported",
message: expect.stringContaining(
"outside the pinned CPython 3.7–3.13 table",
),
}),
);
});
it("reports a short unknown header before unsupported magic, and bad CR LF before either", () => {
const unknown = pythonPycHeader(1).subarray(0, 4);
expect(() => parse(unknown)).toThrow(
expect.objectContaining({
kind: "malformed",
message:
"Selected file is shorter than a 16-byte CPython 3.7+ pyc header.",
}),
);
const badTrailer = Buffer.from(unknown);
badTrailer[3] = 0;
expect(() => parse(badTrailer)).toThrow(
expect.objectContaining({
kind: "malformed",
message: "Pyc magic is not a little-endian integer followed by CR LF.",
}),
);
});
it("classifies the 12-byte 3.7 alpha header as unsupported", () => {
for (const magic of [3390, 3391]) {
const header = Buffer.alloc(12);
@@ -151,6 +199,12 @@ it("classifies the 12-byte 3.7 alpha header as unsupported", () => {
message: expect.stringContaining("unsupported 12-byte CPython header"),
}),
);
expect(() => parse(header.subarray(0, 4))).toThrow(
expect.objectContaining({
kind: "unsupported",
message: expect.stringContaining("unsupported 12-byte CPython header"),
}),
);
}
});
+15 -10
View File
@@ -1,3 +1,4 @@
import { observePythonBytecodePrefix } from "../domain/python/pythonBytecodeIdentity.js";
import { createHash } from "node:crypto";
import { decodeMarshalUtf8 } from "../domain/python/marshalUtf8.js";
import {
@@ -6,7 +7,7 @@ import {
PYTHON_PYC_HASH_BASED,
PYTHON_PYC_HEADER_BYTES,
PYTHON_PYC_INT_PREVIEW_BITS,
pythonPycMagicEntry,
pythonPycMarshalProfile,
type InspectPythonPycInput,
type PythonPyc,
type PythonPycCodeLayout,
@@ -205,20 +206,24 @@ export const parsePythonPyc = (
): PythonPyc => {
if (bytes.length !== artifact.bytes)
malformed("Selected artifact length disagrees with the retained bytes.");
if (bytes.length < 4) malformed("Selected file is shorter than a pyc magic.");
if (bytes[2] !== 0x0d || bytes[3] !== 0x0a)
malformed("Pyc magic is not a little-endian integer followed by CR LF.");
const magic = bytes.readUInt16LE(0);
const mapped = pythonPycMagicEntry(magic);
if (mapped !== null && mapped.header_bytes !== PYTHON_PYC_HEADER_BYTES)
const prefix = observePythonBytecodePrefix(bytes);
if (prefix.state === "incomplete")
return malformed("Selected file is shorter than a pyc magic.");
if (prefix.state === "invalid-crlf")
return malformed(
"Pyc magic is not a little-endian integer followed by CR LF.",
);
const { magic, identity } = prefix;
const mapped = pythonPycMarshalProfile(magic);
if (identity !== null && identity.headerBytes !== PYTHON_PYC_HEADER_BYTES)
return unsupported(
`Pyc magic ${magic} uses an unsupported ${mapped.header_bytes}-byte CPython header.`,
`Pyc magic ${magic} uses an unsupported ${identity.headerBytes}-byte CPython header.`,
);
if (bytes.length < PYTHON_PYC_HEADER_BYTES)
malformed(
"Selected file is shorter than a 16-byte CPython 3.7+ pyc header.",
);
if (mapped === null)
if (mapped === null || identity === null)
return unsupported(
`Pyc magic ${magic} is outside the pinned CPython 3.7–3.13 table.`,
);
@@ -226,7 +231,7 @@ export const parsePythonPyc = (
const hashBased = (flags & PYTHON_PYC_HASH_BASED) !== 0;
const header = {
magic,
python_version: mapped.python_version,
python_version: identity.pythonVersion,
code_layout: mapped.code_layout,
flags,
hash_based: hashBased,