Files
bot-bottle/docs/demo.tape
T
didericis 030a6bc793
test / unit (push) Successful in 14s
test / integration (push) Successful in 29s
refactor(demo): drive recording through real cli.py instead of a harness
The previous demo harness called the backend Python API directly,
which didn't match what a user typing `./cli.py start <agent>` would
actually see. The recording now goes through the real CLI surface:

- claude-bottle.demo.json + scripts/demo-setup.sh stage a demo
  manifest (one bottle, FAKE_TOKEN env, one unreachable git upstream)
  alongside a dummy SSH identity at ~/.cache/claude-bottle-demo/.
- docs/demo.tape types `./cli.py start demo`, answers the y/N
  preflight, and runs four bash probes via claude's `!` prefix
  (curl x3 + git push), so the recording shows real preflight output
  and real probe results.
- scripts/demo.sh wraps setup -> cli.py -> teardown for human use;
  scripts/demo-record.sh does the same around `vhs docs/demo.tape`.
- .gitignore picks up claude-bottle.json so a user's local manifest
  doesn't get tracked alongside .example / .demo siblings.

scripts/demo_harness.py is removed -- its behavior is fully replaced
by the cli.py + `!` flow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 01:26:41 -04:00

72 lines
2.6 KiB
VHS

# VHS tape — drives `./cli.py start demo` interactively and runs four
# bash probes via claude's `!` prefix. Setup (manifest + dummy SSH key
# + image pre-warm) and teardown happen outside the tape; record via
# `bash scripts/demo-record.sh`, which wraps both.
#
# Re-record when the probe results, manifest, or cli.py preflight
# rendering change.
Output docs/demo.gif
Set Shell "bash"
Set FontSize 13
Set Width 1180
Set Height 780
Set Padding 20
Set Theme "Catppuccin Mocha"
Set TypingSpeed 40ms
Hide
Type "clear"
Enter
Show
# Real cli.py invocation — what a user with claude-bottle.json in cwd
# would type. The bottle declares one allowlist (only baked-in
# defaults), one git upstream (unreachable on purpose so gitleaks runs
# before the gate would forward), and a FAKE_TOKEN env var shaped like
# a GitHub PAT.
Type "./cli.py start demo"
Enter
Sleep 8s
# Confirm the y/N preflight. cli.py reads from /dev/tty.
Type "y"
Enter
# Wait for the bottle to launch: networks created, pipelock + git-gate
# sidecars started, agent container started, claude boots.
Sleep 22s
# Probe 1 — allowlisted HTTPS reaches an allowlisted host via the
# bumped TLS tunnel. Baseline: the proxy isn't just blocking everything.
Type `! curl --proxy "$HTTPS_PROXY" -sw 'status=%{http_code}\n' -o /dev/null https://raw.githubusercontent.com/git/git/master/README.md`
Enter
Sleep 5s
# Probe 2 — non-allowlisted host. Pipelock's host filter refuses to
# forward; DLP doesn't even get a chance to run.
Type `! curl --proxy "$HTTPS_PROXY" -sw 'status=%{http_code}\n' -o /dev/null http://example.com/`
Enter
Sleep 5s
# Probe 3 — allowlisted host BUT body carries a credential pattern.
# api.anthropic.com is on the baked-in allowlist, so the host check
# passes; the DLP body scanner has to catch the ghp_ pattern.
Type `! curl --proxy "$HTTPS_PROXY" -sw 'status=%{http_code}\n' -o /dev/null --data "token=$FAKE_TOKEN" http://api.anthropic.com/dlp-probe`
Enter
Sleep 5s
# Probe 4 — git push of a file containing an AKIA-shaped key. The
# bottle's ~/.gitconfig rewrites the upstream URL to the git-gate via
# `insteadOf`, so this push hits the gate, gitleaks runs in the
# pre-receive hook, and rejects the ref before the gate would forward.
Type `! cd /tmp && rm -rf r && git init -qb main r && cd r && git config user.email demo@x && git config user.name demo && echo AKIAQRJHK7N5ZPM2VXTL > leak.txt && git add . && git commit -qm leak && git push ssh://git@upstream.invalid/path.git main`
Enter
Sleep 10s
# Leave claude. The launcher tears down the container, sidecars, and
# networks on session end.
Ctrl+D
Sleep 4s