feat: add JSON assembly editor

This commit is contained in:
2025-10-03 03:10:26 -06:00
parent 211b4262aa
commit 0e3304ef95
10 changed files with 1541 additions and 353 deletions

View File

@@ -1,9 +1,11 @@
import os
import re
import asyncio
import tempfile
import uuid
import time
import subprocess
from typing import Dict, List
ROLE_NAME = 'script_exec_system'
@@ -14,23 +16,74 @@ def _project_root():
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
def _run_powershell_script_content(content: str):
def _sanitize_env_map(raw) -> Dict[str, str]:
env: Dict[str, str] = {}
if isinstance(raw, dict):
for key, value in raw.items():
if key is None:
continue
name = str(key).strip()
if not name:
continue
env_key = re.sub(r"[^A-Za-z0-9_]", "_", name).upper()
if not env_key:
continue
if isinstance(value, bool):
env_val = "True" if value else "False"
elif value is None:
env_val = ""
else:
env_val = str(value)
env[env_key] = env_val
return env
def _ps_literal(value: str) -> str:
return "'" + value.replace("'", "''") + "'"
def _build_wrapped_script(content: str, env_map: Dict[str, str], timeout_seconds: int) -> str:
inner_lines: List[str] = []
for key, value in (env_map or {}).items():
if not key:
continue
inner_lines.append(f"$Env:{key} = {_ps_literal(value)}")
inner_lines.append(content or "")
inner = "\n".join(line for line in inner_lines if line is not None)
script_block = "$__BorealisScript = {\n" + inner + "\n}\n"
if timeout_seconds and timeout_seconds > 0:
block = (
"$job = Start-Job -ScriptBlock $__BorealisScript\n"
f"if (Wait-Job -Job $job -Timeout {timeout_seconds}) {{\n"
" Receive-Job $job\n"
"} else {\n"
" Stop-Job $job -Force\n"
f" throw \"Script timed out after {timeout_seconds} seconds\"\n"
"}\n"
)
return script_block + block
return script_block + "& $__BorealisScript\n"
def _run_powershell_script_content(content: str, env_map: Dict[str, str], timeout_seconds: int):
temp_dir = os.path.join(_project_root(), "Temp")
os.makedirs(temp_dir, exist_ok=True)
fd, path = tempfile.mkstemp(prefix="sj_", suffix=".ps1", dir=temp_dir, text=True)
final_content = _build_wrapped_script(content or "", env_map, timeout_seconds)
with os.fdopen(fd, 'w', encoding='utf-8', newline='\n') as fh:
fh.write(content or "")
fh.write(final_content)
ps = os.path.expandvars(r"%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe")
if not os.path.isfile(ps):
ps = "powershell.exe"
try:
flags = 0x08000000 if os.name == 'nt' else 0
proc_timeout = timeout_seconds + 30 if timeout_seconds else 60 * 60
proc = subprocess.run(
[ps, "-ExecutionPolicy", "Bypass", "-NoProfile", "-File", path],
capture_output=True,
text=True,
timeout=60*60,
timeout=proc_timeout,
creationflags=flags,
)
return proc.returncode, proc.stdout or "", proc.stderr or ""
@@ -44,15 +97,16 @@ def _run_powershell_script_content(content: str):
pass
def _run_powershell_via_system_task(content: str):
def _run_powershell_via_system_task(content: str, env_map: Dict[str, str], timeout_seconds: int):
ps_exe = os.path.expandvars(r"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe")
if not os.path.isfile(ps_exe):
ps_exe = 'powershell.exe'
try:
os.makedirs(os.path.join(_project_root(), 'Temp'), exist_ok=True)
script_fd, script_path = tempfile.mkstemp(prefix='sys_task_', suffix='.ps1', dir=os.path.join(_project_root(), 'Temp'), text=True)
final_content = _build_wrapped_script(content or '', env_map, timeout_seconds)
with os.fdopen(script_fd, 'w', encoding='utf-8', newline='\n') as f:
f.write(content or '')
f.write(final_content)
try:
log_dir = os.path.join(_project_root(), 'Logs', 'Agent')
os.makedirs(log_dir, exist_ok=True)
@@ -131,6 +185,29 @@ class Role:
job_id = payload.get('job_id')
script_type = (payload.get('script_type') or '').lower()
content = payload.get('script_content') or ''
raw_env = payload.get('environment')
env_map = _sanitize_env_map(raw_env)
variables = payload.get('variables') if isinstance(payload.get('variables'), list) else []
for var in variables:
if not isinstance(var, dict):
continue
name = str(var.get('name') or '').strip()
if not name:
continue
key = re.sub(r"[^A-Za-z0-9_]", "_", name).upper()
if key in env_map:
continue
default_val = var.get('default')
if isinstance(default_val, bool):
env_map[key] = "True" if default_val else "False"
elif default_val is None:
env_map[key] = ""
else:
env_map[key] = str(default_val)
try:
timeout_seconds = max(0, int(payload.get('timeout_seconds') or 0))
except Exception:
timeout_seconds = 0
if script_type != 'powershell':
await sio.emit('quick_job_result', {
'job_id': job_id,
@@ -139,9 +216,9 @@ class Role:
'stderr': f"Unsupported type: {script_type}"
})
return
rc, out, err = _run_powershell_via_system_task(content)
rc, out, err = _run_powershell_via_system_task(content, env_map, timeout_seconds)
if rc == -999:
rc, out, err = _run_powershell_script_content(content)
rc, out, err = _run_powershell_script_content(content, env_map, timeout_seconds)
status = 'Success' if rc == 0 else 'Failed'
await sio.emit('quick_job_result', {
'job_id': job_id,