"""Bounded, fixed, local dependency checks. No device or network operations.""" from __future__ import annotations import gzip import importlib.util import json import os from pathlib import Path import re import struct import subprocess import sys import tempfile import time import xml.etree.ElementTree as ET MAX_CHECK_OUTPUT = 1024 * 1024 SERIAL_CHECK = ( "$ErrorActionPreference='Stop'; try { " "$t=[System.IO.Ports.SerialPort]; " "@{serial_port_type=$t.FullName;ports=@($t::GetPortNames())} | ConvertTo-Json -Compress " "} catch { exit 1 }" ) def process_lifecycle(): name = "_artemis_device_test_process_lifecycle" if name not in sys.modules: path = Path(__file__).resolve().parent / "skill/scripts/process_lifecycle.py" spec = importlib.util.spec_from_file_location(name, path) module = importlib.util.module_from_spec(spec) sys.modules[name] = module spec.loader.exec_module(module) return sys.modules[name] PROCESS = process_lifecycle() def run_check(argv, directory, deadline, *, binwalk=False): remaining = deadline - time.monotonic() if remaining <= 0.15: return {"status": "budget_exhausted"}, "" env = os.environ.copy() for key in ("FFREPORT", "PYTHONPATH", "PYTHONHOME"): env.pop(key, None) with tempfile.TemporaryDirectory(prefix="artemis-check-config-") as config: if binwalk: env["XDG_CONFIG_HOME"] = config try: completed = PROCESS.run( argv, shell=False, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, cwd=directory, env=env, timeout=min(3.0, remaining), max_output_bytes=MAX_CHECK_OUTPUT, ) except subprocess.TimeoutExpired: return {"status": "timed_out", "error_code": "dependency_check_timeout"}, "" except PROCESS.ManagedProcessError as exc: return { "status": "unknown" if exc.may_have_started else "failed", "error_code": exc.error_code, "may_have_started": exc.may_have_started, }, "" result = { "status": "passed" if completed.returncode == 0 else "failed", "returncode": completed.returncode, } if completed.returncode: result["error_code"] = "dependency_returned_nonzero" return result, "" return result, completed.stdout.decode("utf-8", errors="replace") def check_startup(tool_id, prefix, directory, deadline): arguments = { "ffprobe": ["-version"], "ffmpeg": ["-version"], "tshark": ["--version"], "dumpcap": ["--version"], "nmap": ["--version"], "binwalk": ["--help"], "mediainfo": ["--version"], "powershell": [ "-NoLogo", "-NoProfile", "-NonInteractive", "-Command", "$PSVersionTable.PSVersion.ToString()", ], } result, output = run_check( prefix + arguments[tool_id], directory, deadline, binwalk=tool_id == "binwalk" ) result["check"] = "dll_load_and_required_api" if tool_id == "mediainfo" else "version_or_help" if result["status"] == "passed": # Exit 0 with empty output is only startup evidence, never functional evidence. line = next((line.strip() for line in output.splitlines() if line.strip()), "") # Do not echo arbitrary help text, local paths or environment values into receipts. result["output_present"] = bool(line) if tool_id == "mediainfo" and not line: result.update(status="failed", error_code="mediainfo_version_api_empty") return result def riff_chunk(name, data): return name + struct.pack("> 16) ip = ip[:10] + struct.pack("!H", (~checksum) & 0xFFFF) + ip[12:] packet = ( bytes.fromhex("0200000000020200000000010800") + ip + struct.pack("!4H", 12345, 54321, 12, 0) + payload ) return ( struct.pack(" 0 result["interface_count"] = count elif tool_id == "nmap": root = ET.fromstring(output) hosts = root.find("runstats/hosts") valid = ( root.tag == "nmaprun" and hosts is not None and hosts.get("total") == "0" and not root.findall("host") ) elif tool_id == "binwalk": valid = bool(re.search(r"(?i)gzip|gzip compressed", output)) and bool( re.search(r"(?im)\b256\b|\b0x0*100\b", output) ) elif tool_id == "powershell": data = json.loads(output) valid = data.get("serial_port_type") == "System.IO.Ports.SerialPort" and isinstance( data.get("ports"), list ) if valid: result["port_count"] = len(data["ports"]) except (ValueError, AttributeError, TypeError, ET.ParseError): valid = False if not valid: result.update(status="failed", error_code="fixed_local_sample_result_mismatch") return result def python_runtime(deadline, check_load): modules = { name: {"discovery": "found" if importlib.util.find_spec(name) else "missing"} for name in ("mcp", "dotenv") } startup = {"status": "not_checked"} if check_load: with tempfile.TemporaryDirectory(prefix="artemis-python-check-") as directory: startup, _ = run_check( [ sys.executable, "-I", "-B", "-c", "import mcp, dotenv; print('dependency_imports_loaded')", ], directory, deadline, ) return { "python_bits": struct.calcsize("P") * 8, "version": ".".join(map(str, sys.version_info[:3])), "modules": modules, "startup": startup, "installer_installs_requirements": False, }