Persist assemblies as base64 and decode for execution

This commit is contained in:
2025-10-03 21:16:43 -06:00
parent 304c1e9728
commit 211e37c64c
7 changed files with 370 additions and 21 deletions

View File

@@ -7,6 +7,7 @@ import time
import json
import socket
import subprocess
import base64
from typing import Optional
try:
@@ -39,6 +40,39 @@ def _project_root():
return os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
def _decode_base64_text(value):
if not isinstance(value, str):
return None
stripped = value.strip()
if not stripped:
return ""
cleaned = ''.join(stripped.split())
if not cleaned:
return ""
try:
decoded = base64.b64decode(cleaned, validate=True)
except Exception:
return None
try:
return decoded.decode('utf-8')
except Exception:
return decoded.decode('utf-8', errors='replace')
def _decode_playbook_content(raw_content, encoding_hint):
if isinstance(raw_content, str):
encoding = str(encoding_hint or '').strip().lower()
if encoding in ('base64', 'b64', 'base-64'):
decoded = _decode_base64_text(raw_content)
if decoded is not None:
return decoded
decoded = _decode_base64_text(raw_content)
if decoded is not None:
return decoded
return raw_content
return ''
def _agent_root():
# Resolve Agent root at runtime.
# Typical runtime: <ProjectRoot>/Agent/Borealis/Roles/<this_file>
@@ -801,7 +835,7 @@ try {{
return
# Accept provided run_id or generate one
run_id = (payload.get('run_id') or '').strip() or uuid.uuid4().hex
content = payload.get('playbook_content') or ''
content = _decode_playbook_content(payload.get('playbook_content'), payload.get('playbook_encoding'))
p_name = payload.get('playbook_name') or ''
act_id = payload.get('activity_job_id')
sched_job_id = payload.get('scheduled_job_id')
@@ -874,7 +908,7 @@ try {{
if target and target != hostname.lower():
return
run_id = uuid.uuid4().hex
content = payload.get('script_content') or ''
content = _decode_playbook_content(payload.get('script_content'), payload.get('script_encoding'))
p_name = payload.get('script_name') or ''
self._runs[run_id] = {'cancel': False, 'proc': None}
asyncio.create_task(self._run_playbook(run_id, content, playbook_name=p_name, activity_job_id=payload.get('job_id'), connection='local'))

View File

@@ -4,7 +4,8 @@ import re
import asyncio
import tempfile
import uuid
from typing import Dict, List
import base64
from typing import Dict, List, Optional
from PyQt5 import QtWidgets, QtGui
@@ -65,6 +66,40 @@ def _apply_variable_aliases(env_map: Dict[str, str], variables: List[Dict[str, s
return env_map
def _decode_base64_text(value: str) -> Optional[str]:
if not isinstance(value, str):
return None
stripped = value.strip()
if not stripped:
return ""
try:
cleaned = re.sub(r"\s+", "", stripped)
except Exception:
cleaned = stripped
try:
decoded = base64.b64decode(cleaned, validate=True)
except Exception:
return None
try:
return decoded.decode("utf-8")
except Exception:
return decoded.decode("utf-8", errors="replace")
def _decode_script_content(raw_content, encoding_hint) -> str:
if isinstance(raw_content, str):
encoding = str(encoding_hint or "").strip().lower()
if encoding in ("base64", "b64", "base-64"):
decoded = _decode_base64_text(raw_content)
if decoded is not None:
return decoded
decoded = _decode_base64_text(raw_content)
if decoded is not None:
return decoded
return raw_content
return ""
def _ps_literal(value: str) -> str:
return "'" + value.replace("'", "''") + "'"
@@ -242,7 +277,7 @@ class Role:
job_id = payload.get('job_id')
script_type = (payload.get('script_type') or '').lower()
run_mode = (payload.get('run_mode') or 'current_user').lower()
content = payload.get('script_content') or ''
content = _decode_script_content(payload.get('script_content'), payload.get('script_encoding'))
raw_env = payload.get('environment')
env_map = _sanitize_env_map(raw_env)
variables = payload.get('variables') if isinstance(payload.get('variables'), list) else []

View File

@@ -5,7 +5,8 @@ import tempfile
import uuid
import time
import subprocess
from typing import Dict, List
import base64
from typing import Dict, List, Optional
ROLE_NAME = 'script_exec_system'
@@ -67,6 +68,40 @@ def _apply_variable_aliases(env_map: Dict[str, str], variables: List[Dict[str, s
return env_map
def _decode_base64_text(value: str) -> Optional[str]:
if not isinstance(value, str):
return None
stripped = value.strip()
if not stripped:
return ""
try:
cleaned = re.sub(r"\s+", "", stripped)
except Exception:
cleaned = stripped
try:
decoded = base64.b64decode(cleaned, validate=True)
except Exception:
return None
try:
return decoded.decode("utf-8")
except Exception:
return decoded.decode("utf-8", errors="replace")
def _decode_script_content(raw_content, encoding_hint) -> str:
if isinstance(raw_content, str):
encoding = str(encoding_hint or "").strip().lower()
if encoding in ("base64", "b64", "base-64"):
decoded = _decode_base64_text(raw_content)
if decoded is not None:
return decoded
decoded = _decode_base64_text(raw_content)
if decoded is not None:
return decoded
return raw_content
return ""
def _ps_literal(value: str) -> str:
return "'" + value.replace("'", "''") + "'"
@@ -236,7 +271,7 @@ class Role:
return
job_id = payload.get('job_id')
script_type = (payload.get('script_type') or '').lower()
content = payload.get('script_content') or ''
content = _decode_script_content(payload.get('script_content'), payload.get('script_encoding'))
raw_env = payload.get('environment')
env_map = _sanitize_env_map(raw_env)
variables = payload.get('variables') if isinstance(payload.get('variables'), list) else []