refactor(pipelock): prepare_proxy returns a ProxyPlan

Add a frozen ProxyPlan dataclass to pipelock.py (currently one field:
yaml_path; kept as a class so future proxy-level state has a home).

  - prepare_proxy(spec, stage_dir) now returns pipelock.ProxyPlan
    instead of a raw Path.
  - DockerBottlePlan replaces pipelock_yaml_path + pipelock_yaml_filename
    with a single proxy: ProxyPlan field.
  - launch reads plan.proxy.yaml_path.parent / .name when calling
    pipelock_start. Eventually pipelock_start should just take a Path
    but that's a separate change.
This commit is contained in:
2026-05-11 01:26:38 -04:00
parent 1b8d3bbb94
commit c2cdb7777d
3 changed files with 21 additions and 11 deletions
+9 -9
View File
@@ -101,7 +101,7 @@ class DockerBottleBackend(BottleBackend):
prompt_file.write_text("")
prompt_file.chmod(0o600)
pipelock_yaml = self.prepare_proxy(spec, stage_dir)
proxy_plan = self.prepare_proxy(spec, stage_dir)
env_resolve(manifest, spec.agent_name, env_file, args_file)
prompt_file.write_text(agent.prompt)
@@ -120,20 +120,20 @@ class DockerBottleBackend(BottleBackend):
env_file=env_file,
args_file=args_file,
prompt_file=prompt_file,
pipelock_yaml_path=pipelock_yaml,
pipelock_yaml_filename=pipelock_yaml.name,
proxy_plan=proxy_plan,
allowlist_summary=allowlist_summary,
use_runsc=use_runsc,
)
def prepare_proxy(self, spec: BottleSpec, stage_dir: Path) -> Path:
def prepare_proxy(self, spec: BottleSpec, stage_dir: Path) -> pipelock.ProxyPlan:
"""Decide where the pipelock yaml lives in `stage_dir`, delegate
to PipelockProxy to write it, and return the resolved path.
Stage-only: no Docker resources created yet."""
to PipelockProxy to write it, and return the resolved ProxyPlan
for the launch step to consume. Stage-only: no Docker resources
created yet."""
yaml_path = stage_dir / "pipelock.yaml"
bottle_name = spec.manifest.agents[spec.agent_name].bottle
self._proxy.prepare(spec.manifest, bottle_name, yaml_path)
return yaml_path
return pipelock.ProxyPlan(yaml_path=yaml_path)
@contextmanager
def launch(self, plan: BottlePlan) -> Iterator[DockerBottle]:
@@ -186,8 +186,8 @@ class DockerBottleBackend(BottleBackend):
plan.slug,
state["internal_network"],
state["egress_network"],
plan.stage_dir,
plan.pipelock_yaml_filename,
plan.proxy_plan.yaml_path.parent,
plan.proxy_plan.yaml_path.name,
)
container = self._run_agent_container(plan, state["internal_network"])
+2 -2
View File
@@ -12,6 +12,7 @@ from dataclasses import dataclass
from pathlib import Path
from ...log import info
from ...pipelock import ProxyPlan
from .. import BottlePlan
@@ -30,8 +31,7 @@ class DockerBottlePlan(BottlePlan):
env_file: Path
args_file: Path
prompt_file: Path
pipelock_yaml_path: Path
pipelock_yaml_filename: str
proxy_plan: ProxyPlan
allowlist_summary: str
use_runsc: bool
+10
View File
@@ -15,6 +15,7 @@ from __future__ import annotations
import os
import re
import subprocess
from dataclasses import dataclass
from pathlib import Path
from .log import die, info, warn
@@ -123,6 +124,15 @@ def pipelock_allowlist_summary(manifest: Manifest, bottle_name: str) -> str:
# --- Proxy class -----------------------------------------------------------
@dataclass(frozen=True)
class ProxyPlan:
"""Output of a proxy's prepare step; consumed by launch when the
proxy needs to be brought up. Currently single-field (the on-host
yaml path); kept as a dataclass so future proxy state has a home."""
yaml_path: Path
class PipelockProxy:
"""The pipelock egress proxy. Encapsulates the YAML-config
generation (and is the natural home for any future proxy-level