a1180adec1
The docker backend's compose renderer now emits a single `sidecars` service in place of the four per-sidecar services when CLAUDE_BOTTLE_SIDECAR_BUNDLE is truthy. Default (unset/0/ false) keeps the legacy five-service shape so existing operators don't have to migrate atomically; chunks 4-5 flip the default and delete the flag. New module claude_bottle/backend/docker/sidecar_bundle.py owns the bundle image constant (CLAUDE_BOTTLE_SIDECAR_IMAGE env var override + claude-bottle-sidecars:latest default), the Dockerfile reference, the container-name helper, and the flag-parser. The bundle service: - joins both internal + egress networks with aliases for every legacy shortname + per-slug long form so the agent's HTTPS_PROXY URL (which dials `egress` or `claude-bottle-pipelock-<slug>`) keeps resolving with no agent-side change - carries CLAUDE_BOTTLE_SIDECAR_DAEMONS=<csv> for the init supervisor to narrow which daemons to start - carries the union of the four prior services' daemon-private env vars (EGRESS_UPSTREAM_PROXY, SUPERVISE_*, token env names) - does NOT carry HTTPS_PROXY/HTTP_PROXY/NO_PROXY — those would route git-gate's git fetches through pipelock by mistake - union'd bind-mounts at the same in-container paths as before HTTPS_PROXY scoping moved into egress_entrypoint.sh so only mitmdump's subprocess sees it. In the legacy four-sidecar shape the env vars also lived in the egress service's compose env; the shell script's export is additionally defensive. Tests: - All 44 existing TestCompose cases pass unchanged (flag off → legacy shape). - 20 new TestSidecarBundleShape cases assert on the bundle's services / aliases / env / volumes / depends_on under the flag. - 8 new TestSidecarBundleFlag cases lock down the env-var parser (unset / 0 / false / no / off → disabled; everything else → enabled). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
"""Sidecar bundle constants + helpers for the Docker backend
|
|
(PRD 0024 chunk 2).
|
|
|
|
The bundle image (built by Dockerfile.sidecars, see PRD 0024
|
|
chunk 1) collapses pipelock + egress + git-gate + supervise into
|
|
one container per bottle. Whether the renderer emits the bundle
|
|
shape (one `sidecars` service) or the legacy four-sidecar shape
|
|
is controlled by `CLAUDE_BOTTLE_SIDECAR_BUNDLE`; chunk 2 ships
|
|
both shapes side by side behind the flag so existing operators
|
|
keep working unchanged while the bundle path soaks.
|
|
|
|
This module is intentionally tiny — just the constants + the
|
|
flag + the container-name helper. The compose-renderer branch
|
|
that consumes it lives in `compose.py`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
|
|
# Bundle image. Defaults to a built-locally tag (built from the
|
|
# repo's Dockerfile.sidecars via compose `build:`). Operators
|
|
# pinning to a published digest can override via env, matching
|
|
# the existing `CLAUDE_BOTTLE_PIPELOCK_IMAGE` shape.
|
|
SIDECAR_BUNDLE_IMAGE = os.environ.get(
|
|
"CLAUDE_BOTTLE_SIDECAR_IMAGE",
|
|
"claude-bottle-sidecars:latest",
|
|
)
|
|
|
|
SIDECAR_BUNDLE_DOCKERFILE = "Dockerfile.sidecars"
|
|
|
|
|
|
def sidecar_bundle_container_name(slug: str) -> str:
|
|
"""`claude-bottle-sidecars-<slug>`. Same prefix scheme as the
|
|
per-sidecar containers it replaces, so the dashboard's
|
|
discovery-by-prefix logic keeps working."""
|
|
return f"claude-bottle-sidecars-{slug}"
|
|
|
|
|
|
def sidecar_bundle_enabled(env: dict[str, str] | None = None) -> bool:
|
|
"""Feature-flag check. The flag is opt-in for chunk 2:
|
|
unset / "" / "0" / "false" → legacy four-sidecar shape;
|
|
anything else → bundle shape. Chunks 4-5 flip the default and
|
|
then delete the flag.
|
|
|
|
`env` defaults to `os.environ` at call time so tests can
|
|
monkey-patch the environment without re-importing the module."""
|
|
if env is None:
|
|
env = dict(os.environ)
|
|
raw = env.get("CLAUDE_BOTTLE_SIDECAR_BUNDLE", "").strip().lower()
|
|
return raw not in ("", "0", "false", "no", "off")
|