PRD 0003: Bottle Backend abstraction #5

Merged
didericis merged 44 commits from add-bottle-factory-abstraction into main 2026-05-11 14:49:43 -04:00
3 changed files with 21 additions and 11 deletions
Showing only changes of commit c2cdb7777d - Show all commits
+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