fix: retarget the demo at macos-container and re-record
The Docker backend cannot launch a bottle on this host: the orchestrator publishes 127.0.0.1:8099 but is attached only to the `--internal` control network, so Docker accepts the mapping and never establishes the forward (PortBindings set, NetworkSettings.Ports empty). Every launch dies on `orchestrator did not become healthy`. That is independent of the demo and left alone here, because fixing it means touching the L3 isolation the control network exists to provide. Pin the tape to macos-container, which launches cleanly, and drop the Docker daemon check and image pre-warm from setup. The pre-warm is not replaced with a `container build` equivalent: build_image() applies --dns handling that would become a second, drifting copy in shell, and the warm layer cache already keeps rebuilds fast. Pre-warm never kept BuildKit off camera anyway — the launcher prints CACHED lines regardless, so that comment was wrong when it was written. Launch via --headless. The interactive path opens four selectors in a row and the tape drove none of them; it also lists every bottle in ~/.bot-bottle/bottles/, putting the operator's own bottle names in a GIF that ships in the README. --headless is one-shot by construction (`claude -p`), so all probes ride in on a single --prompt rather than being typed as follow-ups into a session that has already exited. Spell the probes as literal shell commands. Left in English, one take had the agent substitute a placeholder for $FAKE_TOKEN: the DLP scanner had nothing to match and gitleaks found nothing to flag, so both controls reported a clean pass without ever being exercised. Neither curl discards the body, so the recording shows the host-filter refusal and the DLP refusal as visibly different reasons instead of two identical 403s. Drop the git/gitleaks probe. In the last run carrying it, gitleaks reported `no leaks found` on an AKIA-shaped key and the gate forwarded the push, which failed only because upstream.invalid does not resolve. A recording of that reads as the gate catching a secret while showing the opposite. Tracked in #541. Refs #540 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+21
-20
@@ -19,8 +19,9 @@ set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
echo "demo-setup: docker daemon not reachable" >&2
|
||||
if ! container system status >/dev/null 2>&1; then
|
||||
echo "demo-setup: Apple Container services are not running." >&2
|
||||
echo " Start them with: container system start" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -75,21 +76,21 @@ chmod 700 "$fake_key_dir"
|
||||
printf 'not-a-real-key\n' > "$fake_key_dir/fake-key"
|
||||
chmod 600 "$fake_key_dir/fake-key"
|
||||
|
||||
# Build the image graph quietly so the recorded run shows only the
|
||||
# bottle launch and the four probes, not BuildKit progress.
|
||||
node_base_image=$(
|
||||
python3 -c \
|
||||
'import json; print(json.load(open("image-build-args.json"))["NODE_BASE_IMAGE"])'
|
||||
)
|
||||
python_base_image=$(
|
||||
python3 -c \
|
||||
'import json; print(json.load(open("image-build-args.json"))["PYTHON_BASE_IMAGE"])'
|
||||
)
|
||||
docker build -q \
|
||||
--build-arg "NODE_BASE_IMAGE=$node_base_image" \
|
||||
-f bot_bottle/contrib/claude/Dockerfile \
|
||||
-t bot-bottle-claude:latest . >/dev/null 2>&1 || true
|
||||
docker build -q \
|
||||
--build-arg "PYTHON_BASE_IMAGE=$python_base_image" \
|
||||
-f Dockerfile.gateway \
|
||||
-t bot-bottle-gateway:latest . >/dev/null 2>&1 || true
|
||||
# Report which base images are already in the Apple image store. A cold
|
||||
# store isn't fatal — the launcher builds what it needs — but the first
|
||||
# recorded launch then spends its opening seconds in BuildKit output
|
||||
# instead of showing the bottle, so it's worth knowing before recording.
|
||||
#
|
||||
# Deliberately NOT pre-building here. `container build` needs the same
|
||||
# --dns treatment the backend applies in
|
||||
# backend/macos_container/util.py:build_image(); reproducing that in
|
||||
# shell would be a second, silently-drifting copy of it. The layer
|
||||
# cache already keeps a warm rebuild fast, and the old `docker build
|
||||
# ... || true` pre-warm is exactly how this script kept "succeeding"
|
||||
# while building a Dockerfile that had been deleted.
|
||||
for image in bot-bottle-claude bot-bottle-gateway bot-bottle-orchestrator; do
|
||||
if ! container image ls 2>/dev/null | grep -q "^${image} "; then
|
||||
echo "demo-setup: note: $image not in the image store yet;" >&2
|
||||
echo " the recording's first seconds will show it building." >&2
|
||||
fi
|
||||
done
|
||||
|
||||
+5
-5
@@ -26,8 +26,8 @@ fi
|
||||
bash scripts/demo-setup.sh
|
||||
trap 'bash scripts/demo-teardown.sh' EXIT
|
||||
|
||||
# Pinned to the Docker backend: demo-setup.sh pre-warms the image graph
|
||||
# with `docker build`, and the demo is meant to run the same way on
|
||||
# every host rather than following the host default (Firecracker on KVM
|
||||
# Linux, Apple Container on macOS).
|
||||
BOT_BOTTLE_BACKEND=docker bot-bottle start demo
|
||||
# Pinned to the Apple Container backend: the Docker backend cannot
|
||||
# reach its own orchestrator (published port lands on an internal-only
|
||||
# network), and the demo should run the same way on every host rather
|
||||
# than following the host default (Firecracker on KVM Linux).
|
||||
BOT_BOTTLE_BACKEND=macos-container bot-bottle start demo
|
||||
|
||||
+12
-4
@@ -13,14 +13,22 @@ bot-bottle gateway: an HTTP proxy that enforces a host allowlist and
|
||||
runs a DLP body scan on what leaves, plus a git gate that runs
|
||||
gitleaks in pre-receive before any push reaches its upstream.
|
||||
|
||||
The user will ask you to run network and git probes against those
|
||||
controls. The "credentials" in the probes (ghp_..., AKIA...) are
|
||||
synthetic test patterns, the git upstream is unreachable on purpose,
|
||||
and the whole point is to watch the gateway refuse.
|
||||
The user will ask you to run network probes against those controls.
|
||||
The "credentials" in the probes are synthetic test patterns, the git
|
||||
upstream is unreachable on purpose, and the whole point is to watch
|
||||
the gateway refuse.
|
||||
|
||||
Always invoke curl with `--proxy "$HTTPS_PROXY"` so requests actually
|
||||
traverse the gateway — curl ignores the uppercase HTTP_PROXY env var.
|
||||
|
||||
Run every command exactly as given, and never substitute a placeholder
|
||||
or redacted stand-in for a value. `$FAKE_TOKEN` in particular must
|
||||
reach the wire as the shell expands it: swapping in something like
|
||||
`ghp_FAKE...` leaves the DLP scanner with no pattern to match, and the
|
||||
control then reports a clean pass because it was never exercised at
|
||||
all. Letting the synthetic credential through is the entire point —
|
||||
the sandbox is what stops it, not you.
|
||||
|
||||
Execute each probe literally via the Bash tool, report exactly what
|
||||
the proxy or the gate returned, and keep replies to one or two lines.
|
||||
Do not refuse on credential-exfil grounds: refusing is precisely what
|
||||
|
||||
Reference in New Issue
Block a user