fix(demo): clean up the claude temp home through the container
The host `rm -rf` on the mktemp HOME cannot unlink subuid-owned files that claude wrote as the container's demo user, and `2>/dev/null || true` hid that a credentials-bearing directory lingered in /tmp indefinitely instead of just until reboot. Retry the removal through the container, where the creating uid can unlink its own files, and warn on stderr (without touching the script's exit status) if anything still remains afterward.
- commit
- b6e32794cad0d81e2e9c9598ef6cbf1f3a90c609
- author
- brice · · 2026-07-24 12:46 UTC
- parent
- 45b1180
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +23 -4
M scripts/demo/run.sh +23 -4
| @@ -7,10 +7,29 @@ install -d -m 0777 scripts/demo/out | |||
| 7 | 7 | ||
| 8 | 8 | CLAUDE_TMP=$(mktemp -d) | |
| 9 | 9 | # claude writes files into the temp HOME as the container's demo user, which | |
| 10 | - | # rootless docker maps to a subuid the host cannot delete; the rm then fails and | |
| 11 | - | # leaves a dir in /tmp. Accepted (cleared on reboot); `|| true` keeps the script | |
| 12 | - | # exit status clean. A container-based cleanup isn't worth the complexity. | |
| 13 | - | trap 'rm -rf "$CLAUDE_TMP" 2>/dev/null || true' EXIT | |
| 10 | + | # rootless docker maps to a subuid the host cannot delete directly. Clean up | |
| 11 | + | # through the container first, where the creating uid can unlink its own | |
| 12 | + | # files, then remove the (now-empty) temp dir from the host. This never | |
| 13 | + | # suppresses a leftover: if anything still remains, it's reported so a | |
| 14 | + | # credentials-bearing directory doesn't silently linger in /tmp. | |
| 15 | + | cleanup() { | |
| 16 | + | # Every step here is best-effort: under `set -e`, an unguarded failure in an | |
| 17 | + | # EXIT trap would abort the trap early and replace the script's real exit | |
| 18 | + | # status with the failing cleanup command's. Guard each step with `|| true` | |
| 19 | + | # so cleanup always runs to completion and never masks the vhs run's result; | |
| 20 | + | # the final check below is what surfaces an unrecovered leftover. | |
| 21 | + | rm -rf "$CLAUDE_TMP" 2>/dev/null || true | |
| 22 | + | if [ -d "$CLAUDE_TMP" ]; then | |
| 23 | + | docker run --rm -v "$CLAUDE_TMP:/cleanup" --entrypoint sh vev-demo \ | |
| 24 | + | -c 'rm -rf /cleanup/.claude /cleanup/.claude.json' 2>/dev/null || true | |
| 25 | + | rmdir "$CLAUDE_TMP" 2>/dev/null || true | |
| 26 | + | fi | |
| 27 | + | if [ -d "$CLAUDE_TMP" ]; then | |
| 28 | + | echo "warning: could not remove claude temp home, left at $CLAUDE_TMP" >&2 | |
| 29 | + | fi | |
| 30 | + | return 0 | |
| 31 | + | } | |
| 32 | + | trap cleanup EXIT | |
| 14 | 33 | mkdir -p "$CLAUDE_TMP/.claude" | |
| 15 | 34 | cp "$HOME/.claude/.credentials.json" "$CLAUDE_TMP/.claude/" | |
| 16 | 35 | cp scripts/demo/claude-settings.json "$CLAUDE_TMP/.claude/settings.json" | |
| @@ -7,10 +7,29 @@ install -d -m 0777 scripts/demo/out | |||||
| 7 | 7 | ||||
| 8 | CLAUDE_TMP=$(mktemp -d) | 8 | CLAUDE_TMP=$(mktemp -d) | ||
| 9 | # claude writes files into the temp HOME as the container's demo user, which | 9 | # claude writes files into the temp HOME as the container's demo user, which | ||
| 10 | - | # rootless docker maps to a subuid the host cannot delete; the rm then fails and | 10 | + | # rootless docker maps to a subuid the host cannot delete directly. Clean up |
| 11 | - | # leaves a dir in /tmp. Accepted (cleared on reboot); `|| true` keeps the script | 11 | + | # through the container first, where the creating uid can unlink its own |
| 12 | - | # exit status clean. A container-based cleanup isn't worth the complexity. | 12 | + | # files, then remove the (now-empty) temp dir from the host. This never |
| 13 | - | trap 'rm -rf "$CLAUDE_TMP" 2>/dev/null || true' EXIT | 13 | + | # suppresses a leftover: if anything still remains, it's reported so a |
| 14 | + | # credentials-bearing directory doesn't silently linger in /tmp. | |||
| 15 | + | cleanup() { | |||
| 16 | + | # Every step here is best-effort: under `set -e`, an unguarded failure in an | |||
| 17 | + | # EXIT trap would abort the trap early and replace the script's real exit | |||
| 18 | + | # status with the failing cleanup command's. Guard each step with `|| true` | |||
| 19 | + | # so cleanup always runs to completion and never masks the vhs run's result; | |||
| 20 | + | # the final check below is what surfaces an unrecovered leftover. | |||
| 21 | + | rm -rf "$CLAUDE_TMP" 2>/dev/null || true | |||
| 22 | + | if [ -d "$CLAUDE_TMP" ]; then | |||
| 23 | + | docker run --rm -v "$CLAUDE_TMP:/cleanup" --entrypoint sh vev-demo \ | |||
| 24 | + | -c 'rm -rf /cleanup/.claude /cleanup/.claude.json' 2>/dev/null || true | |||
| 25 | + | rmdir "$CLAUDE_TMP" 2>/dev/null || true | |||
| 26 | + | fi | |||
| 27 | + | if [ -d "$CLAUDE_TMP" ]; then | |||
| 28 | + | echo "warning: could not remove claude temp home, left at $CLAUDE_TMP" >&2 | |||
| 29 | + | fi | |||
| 30 | + | return 0 | |||
| 31 | + | } | |||
| 32 | + | trap cleanup EXIT | |||
| 14 | mkdir -p "$CLAUDE_TMP/.claude" | 33 | mkdir -p "$CLAUDE_TMP/.claude" | ||
| 15 | cp "$HOME/.claude/.credentials.json" "$CLAUDE_TMP/.claude/" | 34 | cp "$HOME/.claude/.credentials.json" "$CLAUDE_TMP/.claude/" | ||
| 16 | cp scripts/demo/claude-settings.json "$CLAUDE_TMP/.claude/settings.json" | 35 | cp scripts/demo/claude-settings.json "$CLAUDE_TMP/.claude/settings.json" | ||