fix(build): validate packaged spawn helpers
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import { spawn } from 'node:child_process'
|
||||
import { existsSync, mkdirSync, statSync } from 'node:fs'
|
||||
import { existsSync, mkdirSync, readFileSync, statSync } from 'node:fs'
|
||||
import { chmod, copyFile, readFile, rm, writeFile } from 'node:fs/promises'
|
||||
import { basename, join, resolve, sep } from 'node:path'
|
||||
import { parseArgs } from 'node:util'
|
||||
@@ -58,6 +58,24 @@ interface RuntimeProduct {
|
||||
spawnHelper: string
|
||||
}
|
||||
|
||||
function spawnHelperBinaryTarget(path: string): string | undefined {
|
||||
const header = readFileSync(path).subarray(0, 20)
|
||||
if (header.length >= 20
|
||||
&& header.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))
|
||||
&& header[4] === 2
|
||||
&& header[5] === 1) {
|
||||
const machine = header.readUInt16LE(18)
|
||||
if (machine === 62) return 'linux-x64'
|
||||
if (machine === 183) return 'linux-arm64'
|
||||
}
|
||||
if (header.length >= 8 && header.readUInt32LE(0) === 0xfeedfacf) {
|
||||
const cpuType = header.readUInt32LE(4)
|
||||
if (cpuType === 0x01000007) return 'macos-x64'
|
||||
if (cpuType === 0x0100000c) return 'macos-arm64'
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function isPlatform(value: string): value is Platform {
|
||||
return (PLATFORMS as readonly string[]).includes(value)
|
||||
}
|
||||
@@ -347,7 +365,17 @@ class SingleExeBuild {
|
||||
+ `checked ${candidates.join(', ')}. Build each runtime on its target platform and architecture.`,
|
||||
)
|
||||
}
|
||||
if (statSync(helper).mode & 0o111) return helper
|
||||
if (statSync(helper).mode & 0o111) {
|
||||
const expected = `${target.platform}-${target.arch}`
|
||||
const actual = spawnHelperBinaryTarget(helper)
|
||||
if (actual !== expected) {
|
||||
throw new Error(
|
||||
`build-exe-for-python-sdk: node-pty spawn-helper binary mismatch: expected ${expected}, `
|
||||
+ `found ${actual ?? 'unsupported format or architecture'} at ${helper}`,
|
||||
)
|
||||
}
|
||||
return helper
|
||||
}
|
||||
throw new Error(`build-exe-for-python-sdk: node-pty spawn-helper is not executable: ${helper}`)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,35 @@ PLATFORMS = {
|
||||
"macos-arm64": ("macosx_11_0_arm64", "dsh-jsonrpc-agent-pkg-macos-arm64"),
|
||||
}
|
||||
SPAWN_HELPER_SUFFIX = "-spawn-helper"
|
||||
EXECUTABLE_TARGETS = {value[1]: key for key, value in PLATFORMS.items()}
|
||||
|
||||
|
||||
def spawn_helper_binary_target(header: bytes) -> str | None:
|
||||
if (
|
||||
len(header) >= 20
|
||||
and header[:4] == b"\x7fELF"
|
||||
and header[4] == 2
|
||||
and header[5] == 1
|
||||
):
|
||||
machine = int.from_bytes(header[18:20], "little")
|
||||
if machine == 62:
|
||||
return "linux-x64"
|
||||
if machine == 183:
|
||||
return "linux-arm64"
|
||||
if len(header) >= 8 and header[:4] == b"\xcf\xfa\xed\xfe":
|
||||
if int.from_bytes(header[4:8], "little") == 0x0100000C:
|
||||
return "macos-arm64"
|
||||
return None
|
||||
|
||||
|
||||
def validate_spawn_helper(path: Path, expected_target: str) -> None:
|
||||
with path.open("rb") as helper:
|
||||
actual_target = spawn_helper_binary_target(helper.read(20))
|
||||
if actual_target != expected_target:
|
||||
raise ValueError(
|
||||
f"runtime spawn helper binary mismatch: expected {expected_target}, "
|
||||
f"found {actual_target or 'unsupported format or architecture'} at {path}"
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
@@ -142,6 +171,7 @@ def stage_runtime(destination: Path, version: str, executable: Path, executable_
|
||||
raise FileNotFoundError(f"runtime spawn helper does not exist: {spawn_helper}")
|
||||
if spawn_helper.stat().st_mode & stat.S_IXUSR == 0:
|
||||
raise PermissionError(f"runtime spawn helper is not executable: {spawn_helper}")
|
||||
validate_spawn_helper(spawn_helper, EXECUTABLE_TARGETS[executable_name])
|
||||
copy_package(ROOT / "python" / "sdk-runtime", destination)
|
||||
rewrite_version(destination / "pyproject.toml", version)
|
||||
runtime_dir = destination / "src" / "deepseek_harness_runtime" / "runtime"
|
||||
@@ -186,6 +216,13 @@ def verify_wheel(
|
||||
mode = archive.getinfo(executable).external_attr >> 16
|
||||
if mode & stat.S_IXUSR == 0:
|
||||
raise RuntimeError(f"{wheel} runtime executable lost its executable bit: {executable}")
|
||||
actual_target = spawn_helper_binary_target(archive.read(helpers[0])[:20])
|
||||
expected_target = EXECUTABLE_TARGETS[platform[1]]
|
||||
if actual_target != expected_target:
|
||||
raise RuntimeError(
|
||||
f"{wheel} spawn helper binary mismatch: expected {expected_target}, "
|
||||
f"found {actual_target or 'unsupported format or architecture'}"
|
||||
)
|
||||
elif runtime_files:
|
||||
raise RuntimeError(f"SDK wheel unexpectedly contains runtime executables: {runtime_files}")
|
||||
if package == "sdk":
|
||||
|
||||
Reference in New Issue
Block a user