fix: replace os.system() with subprocess.run() for security and robustness

- Replace os.system() calls with subprocess.run() using list args to avoid shell injection (CWE-78, Bandit B605/B607)

- Replace assert-based error handling with proper exceptions (ValueError, RuntimeError, FileNotFoundError) that survive python -O (Bandit B101)

- Use sys.executable instead of hardcoded 'python' to ensure correct interpreter (Bandit B607)

Files changed: cmake_build.py, scripts/run_tests.py, compileall.py, amalgamate.py
This commit is contained in:
diiviikk5 2026-02-08 01:44:02 +05:30
parent 24428793fc
commit 6f2366dc2d
4 changed files with 34 additions and 22 deletions

View File

@ -3,9 +3,10 @@ import shutil
import os import os
import sys import sys
import time import time
import subprocess
from typing import List, Dict from typing import List, Dict
assert os.system("python prebuild.py") == 0 subprocess.run([sys.executable, "prebuild.py"], check=True)
ROOT = 'include/pocketpy' ROOT = 'include/pocketpy'
PUBLIC_HEADERS = ['config.h', 'export.h', 'vmath.h', 'pocketpy.h'] PUBLIC_HEADERS = ['config.h', 'export.h', 'vmath.h', 'pocketpy.h']
@ -161,8 +162,9 @@ write_file('amalgamated/pocketpy.h', merge_h_files())
shutil.copy("src2/main.c", "amalgamated/main.c") shutil.copy("src2/main.c", "amalgamated/main.c")
def checked_sh(cmd): def checked_sh(cmd):
ok = os.system(cmd) result = subprocess.run(cmd, shell=True)
assert ok == 0, f"command failed: {cmd}" if result.returncode != 0:
raise RuntimeError(f"command failed (exit code {result.returncode}): {cmd}")
if sys.platform in ['linux', 'darwin']: if sys.platform in ['linux', 'darwin']:
common_flags = "-O1 --std=c11 -lm -ldl -lpthread -Iamalgamated" common_flags = "-O1 --std=c11 -lm -ldl -lpthread -Iamalgamated"

View File

@ -1,8 +1,9 @@
import os import subprocess
import sys import sys
import shutil import shutil
import os
assert os.system("python prebuild.py") == 0 subprocess.run([sys.executable, "prebuild.py"], check=True)
if not os.path.exists("build"): if not os.path.exists("build"):
os.mkdir("build") os.mkdir("build")
@ -14,16 +15,22 @@ if len(sys.argv) > 1:
else: else:
config = 'Release' config = 'Release'
extra_flags = " ".join(sys.argv[2:]) extra_flags = sys.argv[2:]
assert config in ['Debug', 'Release', 'RelWithDebInfo'] if config not in ['Debug', 'Release', 'RelWithDebInfo']:
raise ValueError(f"Invalid config: {config!r}. Must be one of Debug, Release, RelWithDebInfo")
os.chdir("build") os.chdir("build")
code = os.system(f"cmake .. -DPK_ENABLE_MIMALLOC=ON -DPK_ENABLE_DETERMINISM=ON -DCMAKE_BUILD_TYPE={config} {extra_flags}") subprocess.run(
assert code == 0 ["cmake", "..", "-DPK_ENABLE_MIMALLOC=ON", "-DPK_ENABLE_DETERMINISM=ON",
code = os.system(f"cmake --build . --config {config} -j 4") f"-DCMAKE_BUILD_TYPE={config}"] + extra_flags,
assert code == 0 check=True,
)
subprocess.run(
["cmake", "--build", ".", "--config", config, "-j", "4"],
check=True,
)
if sys.platform == "win32": if sys.platform == "win32":
shutil.copy(f"{config}/main.exe", "../main.exe") shutil.copy(f"{config}/main.exe", "../main.exe")

View File

@ -1,5 +1,6 @@
import sys import sys
import os import os
import subprocess
if len(sys.argv) != 4: if len(sys.argv) != 4:
print('Usage: python compileall.py <pocketpy_executable> <source_dir> <output_dir>') print('Usage: python compileall.py <pocketpy_executable> <source_dir> <output_dir>')
@ -10,9 +11,10 @@ source_dir = sys.argv[2]
output_dir = sys.argv[3] output_dir = sys.argv[3]
def do_compile(src_path, dst_path): def do_compile(src_path, dst_path):
assert os.path.isfile(src_path) if not os.path.isfile(src_path):
cmd = f'{pkpy_exe} --compile "{src_path}" "{dst_path}"' raise FileNotFoundError(f"Source file not found: {src_path}")
if os.system(cmd) != 0: result = subprocess.run([pkpy_exe, '--compile', src_path, dst_path])
if result.returncode != 0:
print(src_path) print(src_path)
exit(1) exit(1)

View File

@ -7,11 +7,12 @@ pkpy_exe = 'main.exe' if sys.platform == 'win32' else './main'
def test_file(filepath, cpython=False): def test_file(filepath, cpython=False):
if cpython: if cpython:
return os.system("python " + filepath) == 0 result = subprocess.run([sys.executable, filepath])
code = os.system(pkpy_exe + ' ' + filepath) return result.returncode == 0
if code != 0: result = subprocess.run([pkpy_exe, filepath])
print('Return code:', code) if result.returncode != 0:
return code == 0 print('Return code:', result.returncode)
return result.returncode == 0
def test_dir(path): def test_dir(path):
print("Testing directory:", path) print("Testing directory:", path)
@ -74,11 +75,11 @@ exit()
print(res.stdout) print(res.stdout)
exit(1) exit(1)
code = os.system(f'python compileall.py {pkpy_exe} tests tmp/tests') subprocess.run([sys.executable, 'compileall.py', pkpy_exe, 'tests', 'tmp/tests'], check=True)
assert code == 0
if len(sys.argv) == 2: if len(sys.argv) == 2:
assert 'benchmark' in sys.argv[1] if 'benchmark' not in sys.argv[1]:
raise ValueError(f"Expected 'benchmark' in argument, got: {sys.argv[1]!r}")
test_dir('benchmarks/') test_dir('benchmarks/')
else: else:
test_dir('tests/') test_dir('tests/')