52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
from pathlib import Path
|
|
|
|
import podman
|
|
|
|
from agent.config import settings
|
|
|
|
|
|
class PodmanSandbox:
|
|
def __init__(self):
|
|
# connect to podman socket (rootless)
|
|
self.client = podman.PodmanClient()
|
|
self.container = None
|
|
|
|
async def __aenter__(self):
|
|
# ensure workspace directory exists, create if it doesn't
|
|
workspace_path = Path(settings.safedir).resolve()
|
|
workspace_path.mkdir(parents=True, exist_ok=True)
|
|
|
|
self.container = self.client.containers.run(
|
|
"python:3.14",
|
|
command=["sleep", "60h"],
|
|
detach=True,
|
|
runtime="krun",
|
|
network_mode="none",
|
|
mem_limit="512m",
|
|
volumes={
|
|
str(Path(settings.safedir).absolute()): {
|
|
"bind": "/workspace",
|
|
"mode": "rw",
|
|
}
|
|
},
|
|
working_dir="/workspace",
|
|
remove=True,
|
|
)
|
|
return self
|
|
|
|
def run(self, command: str) -> str:
|
|
"""Execute command in microVM/"""
|
|
exit_code, output = self.container.exec_run(
|
|
["/bin/sh", "-c", command], workdir="/workspace", demux=False
|
|
)
|
|
return output.decode("utf-8", errors="replace")
|
|
|
|
async def __aexit__(self, *args):
|
|
if self.container:
|
|
try:
|
|
self.container.stop()
|
|
except Exception as e:
|
|
# log but don't raise, best effort cleanup
|
|
print(f"Warning: Container cleanup failed: {e}")
|
|
# possibly use logging.warning if we add loggin later
|