Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
1 line
6.8 KiB
JSON
1 line
6.8 KiB
JSON
{"repo": "1stproof/batch-2", "files": {"batch-2-submissions/improofbench/src/proofstack/sandbox/base.py": {"77b4e4b466e958759882302179e7e94d7392a8e7": {"t": 1786068243.5491173, "n": 6479, "h": "40b539d3ba05c1ca", "c": "\"\"\"Sandbox interface for CLI agents.\"\"\"\nfrom __future__ import annotations\n\nimport asyncio\nimport os\nimport shutil\nimport subprocess\nimport tempfile\nfrom dataclasses import dataclass, field\nfrom pathlib import Path\nfrom typing import Iterable, Literal, Mapping\n\n\nSandboxBackend = Literal[\"subprocess\", \"docker\"]\n\n\n# Standard env vars we always pass through; provider keys are added per call.\n# HOME is intentionally NOT in the allowlist — it is always pinned to the\n# sandbox root in ``build_env`` so a model-driven coding CLI cannot read or\n# modify files under the orchestrator's real home directory.\nDEFAULT_ENV_ALLOWLIST: tuple[str, ...] = (\n \"PATH\",\n \"USER\",\n \"LANG\",\n \"LC_ALL\",\n \"TERM\",\n \"TMPDIR\",\n \"PYTHONPATH\",\n)\n\n\n@dataclass\nclass SandboxSpec:\n \"\"\"Resource and isolation knobs for a sandbox invocation.\"\"\"\n\n cpu_limit: int = 2\n memory_gb: int = 4\n timeout_s: int = 900\n env_allowlist: tuple[str, ...] = DEFAULT_ENV_ALLOWLIST\n extra_env: Mapping[str, str] = field(default_factory=dict)\n # Provider-key env names to pass through *if present* in the parent\n # environment. The actual values are read from the parent at spawn\n # time and never written to disk.\n provider_keys: tuple[str, ...] = (\n \"OPENAI_API_KEY\",\n \"ANTHROPIC_API_KEY\",\n \"GOOGLE_API_KEY\",\n \"GEMINI_API_KEY\",\n \"XAI_API_KEY\",\n \"DEEPSEEK_API_KEY\",\n \"GLM_API_KEY\",\n \"MOONSHOT_API_KEY\",\n \"TOGETHER_API_KEY\",\n # Stepfun: README + APIClient use STEPFUN_API_KEY; keep STEP_API_KEY\n # for compatibility with older configs that may still set it.\n \"STEPFUN_API_KEY\",\n \"STEP_API_KEY\",\n )\n\n # --- Backend selection -------------------------------------------------\n # \"subprocess\" — spawn the CLI as a child process on the host, with\n # setrlimit + env-allowlist isolation only. Useful inside trusted\n # containers or for tests.\n #\n # \"docker\" — spawn the CLI inside an ephemeral `docker run --rm`\n # container with dropped capabilities, resource limits, and a\n # writable bind mount for the per-invocation workdir. This is the\n # default for CLI agents.\n backend: SandboxBackend = \"docker\"\n\n # --- Docker-backend-specific knobs -------------------------------------\n # Image to run. Must exist locally (we don't pull automatically).\n # Build with `docker build -t proofstack-sandbox:latest deploy/sandbox/`.\n docker_image: str = \"proofstack-sandbox:latest\"\n # \"bridge\" gives internet access (Codex needs OpenAI); \"none\" for\n # fully-offline smoke tests.\n docker_network: Literal[\"bridge\", \"none\"] = \"bridge\"\n # Hard per-container pid cap. Prevents fork bombs.\n docker_pids_limit: int = 256\n # Some Docker/AppArmor installations reject every exec inside\n # node-based images when no-new-privileges is set. Keep it configurable\n # so Codex sandboxes can still run while retaining the other Docker caps.\n docker_no_new_privileges: bool = True\n # Extra flags passed verbatim to `docker run` (after the safety\n # defaults). For advanced tuning; keep empty by default.\n docker_extra_args: tuple[str, ...] = ()\n\n def build_env(self, *, sandbox_root: Path, extra_path: Iterable[Path] = ()) -> dict[str, str]:\n env: dict[str, str] = {}\n for key in self.env_allowlist:\n if (val := os.environ.get(key)) is not None:\n env[key] = val\n for key in self.provider_keys:\n if (val := os.environ.get(key)) is not None:\n env[key] = val\n env.update(self.extra_env)\n # Prepend extra_path entries to PATH so our finish shim wins.\n path_parts = [str(p) for p in extra_path] + ([env[\"PATH\"]] if \"PATH\" in env else [])\n if path_parts:\n env[\"PATH\"] = os.pathsep.join(path_parts)\n # HOME and TMPDIR are pinned to the sandbox root unconditionally —\n # the parent's HOME must NEVER leak through, even if extra_env or\n # the allowlist would set it.\n env[\"HOME\"] = str(sandbox_root)\n env[\"TMPDIR\"] = str(sandbox_root)\n return env\n\n\n@dataclass\nclass CommandResult:\n cmd: list[str]\n returncode: int\n stdout: str\n stderr: str\n duration_s: float\n\n\nclass Sandbox:\n \"\"\"Per-invocation isolated workdir for a CLI run.\n\n Subclasses (only ``SubprocessSandbox`` for now) provide the actual\n execution. The interface is async to fit the rest of the stack.\n \"\"\"\n\n def __init__(self, spec: SandboxSpec, *, root: Path | None = None) -> None:\n self.spec = spec\n # Resolve to absolute at construction. Several env vars derived\n # from ``self.root`` (HOME, TMPDIR, CODEX_HOME, FINISH_DONE_PATH)\n # get exported into a child whose own cwd is the resolved\n # absolute path; if those env vars were relative, the child\n # would re-resolve them against its (already absolute) cwd\n # and look for a doubled-up path that does not exist. Codex\n # in particular bails with \"Error finding codex home\" in <1s.\n raw_root = root if root is not None else Path(tempfile.mkdtemp(prefix=\"proofstack-sbx-\"))\n self.root = Path(raw_root).resolve()\n self.root.mkdir(parents=True, exist_ok=True)\n self._closed = False\n\n async def write_file(self, relpath: str, content: str | bytes) -> Path:\n path = self.root / relpath\n path.parent.mkdir(parents=True, exist_ok=True)\n if isinstance(content, str):\n path.write_text(content, encoding=\"utf-8\")\n else:\n path.write_bytes(content)\n return path\n\n async def read_file(self, relpath: str) -> str:\n return (self.root / relpath).read_text(encoding=\"utf-8\")\n\n async def run_command(\n self,\n cmd: list[str],\n *,\n cwd: str | None = None,\n timeout_s: int | None = None,\n env_extra: Mapping[str, str] | None = None,\n extra_path: Iterable[Path] = (),\n ) -> CommandResult:\n raise NotImplementedError\n\n async def cleanup(self) -> None:\n if self._closed:\n return\n self._closed = True\n await asyncio.to_thread(shutil.rmtree, self.root, True)\n\n async def __aenter__(self) -> \"Sandbox\":\n return self\n\n async def __aexit__(self, exc_type, exc, tb) -> None:\n await self.cleanup()\n\n\n__all__ = [\n \"CommandResult\",\n \"DEFAULT_ENV_ALLOWLIST\",\n \"Sandbox\",\n \"SandboxSpec\",\n]\n"}}}} |