diff --git a/examples/workspaces/all-java-example/.cb-tests/test001-test-version-on-host.sh b/examples/workspaces/all-java-example/.cb-tests/test001-test-version-on-host.sh index d2ae8d19..1ac59bda 100755 --- a/examples/workspaces/all-java-example/.cb-tests/test001-test-version-on-host.sh +++ b/examples/workspaces/all-java-example/.cb-tests/test001-test-version-on-host.sh @@ -9,6 +9,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -20,8 +26,8 @@ echo "=== Testing Java Version ===" echo "" # Capture java -version output (note: java -version outputs to stderr) -"../../../codingbooth" --variant base --port "${CB_PORT:-50011}" -- 'java -version' 2>&1 -output=$("../../../codingbooth" --variant base --port "${CB_PORT:-50011}" -- 'java -version' 2>&1) || true +"$BOOTH" --variant base --port "${CB_PORT:-50011}" -- 'java -version' 2>&1 +output=$("$BOOTH" --variant base --port "${CB_PORT:-50011}" -- 'java -version' 2>&1) || true echo "$output" echo "" diff --git a/examples/workspaces/all-java-example/.cb-tests/test003-source-call--on-host.sh b/examples/workspaces/all-java-example/.cb-tests/test003-source-call--on-host.sh index 84a3aca4..ad15a349 100755 --- a/examples/workspaces/all-java-example/.cb-tests/test003-source-call--on-host.sh +++ b/examples/workspaces/all-java-example/.cb-tests/test003-source-call--on-host.sh @@ -9,6 +9,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -18,7 +24,7 @@ echo "=== Testing jbang Source Execution ===" echo "" # Run jbang with inline Java source -output=$("../../../codingbooth" --variant base --port "${CB_PORT:-50012}" -- ' +output=$("$BOOTH" --variant base --port "${CB_PORT:-50012}" -- ' cat > /tmp/Test.java << "EOFJAVA" import java.nio.file.*; import java.util.Arrays; @@ -44,7 +50,7 @@ echo "" failed=0 # Check for JDK version line -if grep -q "🚀 JDK:" <<< "$output"; then +if LC_ALL=C grep -q "🚀 JDK:" <<< "$output"; then echo -e "${GREEN}✓${NC} Found JDK version output" else echo -e "${RED}✗${NC} Missing JDK version output" @@ -52,7 +58,7 @@ else fi # Check for CWD line -if grep -q "📁 CWD:" <<< "$output"; then +if LC_ALL=C grep -q "📁 CWD:" <<< "$output"; then echo -e "${GREEN}✓${NC} Found CWD output" else echo -e "${RED}✗${NC} Missing CWD output" @@ -60,7 +66,7 @@ else fi # Check for Args line with expected arguments -if grep -q "🔧 Args: \[one, two 2\]" <<< "$output"; then +if LC_ALL=C grep -q "🔧 Args: \[one, two 2\]" <<< "$output"; then echo -e "${GREEN}✓${NC} Found correct arguments" else echo -e "${RED}✗${NC} Missing or incorrect arguments" diff --git a/examples/workspaces/android-example/device-connect.sh b/examples/workspaces/android-example/device-connect.sh index 0dbba8f9..d7bdf188 100755 --- a/examples/workspaces/android-example/device-connect.sh +++ b/examples/workspaces/android-example/device-connect.sh @@ -8,7 +8,7 @@ # does not run under Docker Desktop's amd64 emulation on Apple Silicon (see the # README's Architecture note), but a real device over the network is unaffected. # -# Run this INSIDE the booth: ../../../codingbooth -- ./device-connect.sh ... +# Run this INSIDE the booth: ../../../booth -- ./device-connect.sh ... # # On the phone: Settings -> Developer options -> Wireless debugging -> # "Pair device with pairing code" shows the IP, a PAIRING port, and a 6-digit @@ -44,7 +44,7 @@ CONNECT_PORT="${4:-}" if ! command -v adb >/dev/null 2>&1; then echo "❌ adb not found on PATH. Is this running inside the booth?" >&2 - echo " Try: ../../../codingbooth -- ./device-connect.sh ..." >&2 + echo " Try: ../../../booth -- ./device-connect.sh ..." >&2 exit 1 fi diff --git a/examples/workspaces/aws-example/.cb-tests/test001-aws-connection-on-host.sh b/examples/workspaces/aws-example/.cb-tests/test001-aws-connection-on-host.sh index 9ac76488..d6574671 100755 --- a/examples/workspaces/aws-example/.cb-tests/test001-aws-connection-on-host.sh +++ b/examples/workspaces/aws-example/.cb-tests/test001-aws-connection-on-host.sh @@ -10,6 +10,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -48,7 +54,7 @@ echo "" # Test 2: AWS connection from inside the container echo "Testing AWS connection from inside container..." -if ../../../codingbooth --variant base --port "${CB_PORT:-50021}" -- ./check-connection.sh; then +if "$BOOTH" --variant base --port "${CB_PORT:-50021}" -- ./check-connection.sh; then echo -e "${GREEN}✓${NC} Container AWS connection test passed" else echo -e "${RED}✗${NC} Container AWS connection test failed" @@ -56,4 +62,4 @@ else fi echo "" -echo -e "${GREEN}All AWS connection tests passed!${NC}" \ No newline at end of file +echo -e "${GREEN}All AWS connection tests passed!${NC}" diff --git a/examples/workspaces/dind-example/.cb-tests/test001-running-dind-on-host.sh b/examples/workspaces/dind-example/.cb-tests/test001-running-dind-on-host.sh index 3335cbb6..1b1bf844 100755 --- a/examples/workspaces/dind-example/.cb-tests/test001-running-dind-on-host.sh +++ b/examples/workspaces/dind-example/.cb-tests/test001-running-dind-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -61,7 +67,7 @@ sleep 1 # Start workspace in daemon mode with fixed port mapping echo "Starting codingbooth..." -../../../codingbooth --no-browser --variant base --port "${CB_PORT:-50071}" --daemon --name "$CONTAINER_NAME" -p "$CONTAINER_PORT":8080 || true +"$BOOTH" --no-browser --variant base --port "${CB_PORT:-50071}" --daemon --name "$CONTAINER_NAME" -p "$CONTAINER_PORT":8080 || true # Wait for booth to be ready sleep 2 diff --git a/examples/workspaces/egress-allowlist-extra-example/.cb-tests/test001-egress-on-host.sh b/examples/workspaces/egress-allowlist-extra-example/.cb-tests/test001-egress-on-host.sh index f54bf6fc..fa57870f 100755 --- a/examples/workspaces/egress-allowlist-extra-example/.cb-tests/test001-egress-on-host.sh +++ b/examples/workspaces/egress-allowlist-extra-example/.cb-tests/test001-egress-on-host.sh @@ -5,6 +5,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -16,7 +22,7 @@ fail() { echo -e "${RED}✗${NC} $1"; exit 1; } echo "=== test001: egress allowlist + extra (non-DinD) ===" -if ../../../codingbooth --variant base --version latest --port "${CB_PORT:-50281}" --name egress-allowlist-extra-example --egress -- ./.cb-tests/test-on-container.sh; then +if "$BOOTH" --variant base --version latest --port "${CB_PORT:-50281}" --name egress-allowlist-extra-example --egress -- ./.cb-tests/test-on-container.sh; then pass "Egress non-DinD test passed" else fail "Egress non-DinD test failed" diff --git a/examples/workspaces/egress-envoy-example/.cb-tests/test001-egress-on-host.sh b/examples/workspaces/egress-envoy-example/.cb-tests/test001-egress-on-host.sh index 48b1db6d..2fd05f52 100755 --- a/examples/workspaces/egress-envoy-example/.cb-tests/test001-egress-on-host.sh +++ b/examples/workspaces/egress-envoy-example/.cb-tests/test001-egress-on-host.sh @@ -5,6 +5,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -16,7 +22,7 @@ fail() { echo -e "${RED}✗${NC} $1"; exit 1; } echo "=== test001: egress envoy policy (non-DinD) ===" -if ../../../codingbooth --variant base --version latest --port "${CB_PORT:-50291}" --name egress-envoy-example --egress -- ./.cb-tests/test-on-container.sh; then +if "$BOOTH" --variant base --version latest --port "${CB_PORT:-50291}" --name egress-envoy-example --egress -- ./.cb-tests/test-on-container.sh; then pass "Egress non-DinD test passed" else fail "Egress non-DinD test failed" diff --git a/examples/workspaces/firebase-example/.cb-tests/test001-firebase-connection-on-host.sh b/examples/workspaces/firebase-example/.cb-tests/test001-firebase-connection-on-host.sh index 0fa0b857..0a0b6ac9 100755 --- a/examples/workspaces/firebase-example/.cb-tests/test001-firebase-connection-on-host.sh +++ b/examples/workspaces/firebase-example/.cb-tests/test001-firebase-connection-on-host.sh @@ -10,6 +10,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -55,7 +61,7 @@ echo "" # Test 2: Firebase connection from inside the container echo "Testing Firebase connection from inside container..." -if ../../../codingbooth --variant base --port "${CB_PORT:-50091}" -- ./check-connection.sh; then +if "$BOOTH" --variant base --port "${CB_PORT:-50091}" -- ./check-connection.sh; then echo -e "${GREEN}✓${NC} Container Firebase connection test passed" else echo -e "${RED}✗${NC} Container Firebase connection test failed" diff --git a/examples/workspaces/firebase-example/README.md b/examples/workspaces/firebase-example/README.md index 0337b015..f9bc5f69 100644 --- a/examples/workspaces/firebase-example/README.md +++ b/examples/workspaces/firebase-example/README.md @@ -33,7 +33,7 @@ This means: ### From Host ```bash -../../../codingbooth -- ./test-connection.sh +../../../booth -- ./test-connection.sh ``` ### From Container diff --git a/examples/workspaces/gcloud-example/.cb-tests/test001-gcloud-connection-on-host.sh b/examples/workspaces/gcloud-example/.cb-tests/test001-gcloud-connection-on-host.sh index 73c08092..3ac5fcbd 100755 --- a/examples/workspaces/gcloud-example/.cb-tests/test001-gcloud-connection-on-host.sh +++ b/examples/workspaces/gcloud-example/.cb-tests/test001-gcloud-connection-on-host.sh @@ -10,6 +10,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -48,7 +54,7 @@ echo "" # Test 2: gcloud connection from inside the container echo "Testing gcloud connection from inside container..." -if ../../../codingbooth --variant base --port "${CB_PORT:-50111}" -- ./check-connection.sh; then +if "$BOOTH" --variant base --port "${CB_PORT:-50111}" -- ./check-connection.sh; then echo -e "${GREEN}✓${NC} Container gcloud connection test passed" else echo -e "${RED}✗${NC} Container gcloud connection test failed" diff --git a/examples/workspaces/go-example/.cb-tests/test001-build-and-run-on-host.sh b/examples/workspaces/go-example/.cb-tests/test001-build-and-run-on-host.sh index 5fd7538f..e6a38756 100755 --- a/examples/workspaces/go-example/.cb-tests/test001-build-and-run-on-host.sh +++ b/examples/workspaces/go-example/.cb-tests/test001-build-and-run-on-host.sh @@ -46,14 +46,14 @@ else fi # Check for tree output (the emoji tree structure) -if grep -q "📁" <<< "$output"; then +if LC_ALL=C grep -q "📁" <<< "$output"; then echo -e "${GREEN}✓${NC} Found directory emoji in output" else echo -e "${RED}✗${NC} Missing directory emoji in output" failed=1 fi -if grep -q "📄" <<< "$output"; then +if LC_ALL=C grep -q "📄" <<< "$output"; then echo -e "${GREEN}✓${NC} Found file emoji in output" else echo -e "${RED}✗${NC} Missing file emoji in output" diff --git a/examples/workspaces/java-example/.cb-tests/test001-jbang-on-host.sh b/examples/workspaces/java-example/.cb-tests/test001-jbang-on-host.sh index bb9c8729..564ca3d2 100755 --- a/examples/workspaces/java-example/.cb-tests/test001-jbang-on-host.sh +++ b/examples/workspaces/java-example/.cb-tests/test001-jbang-on-host.sh @@ -37,7 +37,7 @@ echo "" failed=0 # Check for JDK version -if grep -q "🚀 JDK:" <<< "$output"; then +if LC_ALL=C grep -q "🚀 JDK:" <<< "$output"; then echo -e "${GREEN}✓${NC} Found JDK version in output" else echo -e "${RED}✗${NC} Missing JDK version in output" @@ -45,7 +45,7 @@ else fi # Check for current working directory -if grep -q "📁 CWD:" <<< "$output"; then +if LC_ALL=C grep -q "📁 CWD:" <<< "$output"; then echo -e "${GREEN}✓${NC} Found CWD in output" else echo -e "${RED}✗${NC} Missing CWD in output" @@ -53,7 +53,7 @@ else fi # Check for args display -if grep -q "🔧 Args:" <<< "$output"; then +if LC_ALL=C grep -q "🔧 Args:" <<< "$output"; then echo -e "${GREEN}✓${NC} Found Args in output" else echo -e "${RED}✗${NC} Missing Args in output" diff --git a/examples/workspaces/java-example/run-example-on-host.sh b/examples/workspaces/java-example/run-example-on-host.sh index 4bf9fe57..7f623ced 100755 --- a/examples/workspaces/java-example/run-example-on-host.sh +++ b/examples/workspaces/java-example/run-example-on-host.sh @@ -3,8 +3,13 @@ # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } -../../../codingbooth --variant base --port 22000 -- ' +"$BOOTH" --variant base --port 22000 -- ' jbang --quiet - <&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -39,7 +45,7 @@ sleep 1 # Start workspace in daemon mode echo "Starting codingbooth..." -../../../codingbooth --no-browser --daemon --variant base --port "${CB_PORT:-50161}" --name "$CONTAINER_NAME" -p "$CONTAINER_PORT":8080 || true +"$BOOTH" --no-browser --daemon --variant base --port "${CB_PORT:-50161}" --name "$CONTAINER_NAME" -p "$CONTAINER_PORT":8080 || true # Wait for npm install to complete (up to 120 seconds) echo "Waiting for npm install to complete..." diff --git a/examples/workspaces/js-example/.cb-tests/test002-host-accessibility.sh b/examples/workspaces/js-example/.cb-tests/test002-host-accessibility.sh index 39f26426..00f26a93 100755 --- a/examples/workspaces/js-example/.cb-tests/test002-host-accessibility.sh +++ b/examples/workspaces/js-example/.cb-tests/test002-host-accessibility.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -43,7 +49,7 @@ sleep 1 # Start workspace in daemon mode with fixed port mappings echo "Starting codingbooth..." -../../../codingbooth --no-browser --daemon --variant base --port "${CB_PORT:-50162}" --name "$CONTAINER_NAME" -p "$API_HOST_PORT":3000 -p "$VITE_HOST_PORT":5173 || true +"$BOOTH" --no-browser --daemon --variant base --port "${CB_PORT:-50162}" --name "$CONTAINER_NAME" -p "$API_HOST_PORT":3000 -p "$VITE_HOST_PORT":5173 || true # Wait for npm install to complete (up to 120 seconds) echo "Waiting for npm install to complete..." @@ -78,16 +84,20 @@ echo "Starting server inside container..." docker exec "$CONTAINER_NAME" bash -c "cd /home/coder/code && just start" > /dev/null 2>&1 pass "Server started" -# Wait for server to be ready -sleep 2 - -# Check servers are accessible from host +# Check servers are accessible from host, polling while they start +# (the tsx-compiled API server can take well over a few seconds) echo "Checking servers from host..." -if API_PORT=$API_PORT VITE_PORT=$VITE_PORT ./check-server.sh --expect=up; then - pass "Servers accessible from host" -else - fail "Servers should be accessible from host" -fi +WAIT_COUNT=0 +until API_PORT=$API_PORT VITE_PORT=$VITE_PORT ./check-server.sh --expect=up > /dev/null 2>&1; do + WAIT_COUNT=$((WAIT_COUNT + 1)) + if [ "$WAIT_COUNT" -ge 60 ]; then + API_PORT=$API_PORT VITE_PORT=$VITE_PORT ./check-server.sh --expect=up || true + fail "Servers should be accessible from host" + fi + sleep 1 +done +API_PORT=$API_PORT VITE_PORT=$VITE_PORT ./check-server.sh --expect=up +pass "Servers accessible from host" # Stop server echo "Stopping server..." diff --git a/examples/workspaces/kind-app-example/.cb-tests/test001-kind-cluster-on-host.sh b/examples/workspaces/kind-app-example/.cb-tests/test001-kind-cluster-on-host.sh index a9e5c345..013467e4 100755 --- a/examples/workspaces/kind-app-example/.cb-tests/test001-kind-cluster-on-host.sh +++ b/examples/workspaces/kind-app-example/.cb-tests/test001-kind-cluster-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -60,7 +66,7 @@ sleep 1 # Start booth in daemon mode echo "Starting booth with KinD..." -../../../codingbooth --no-browser --keep-alive --daemon --variant base --port "${CB_PORT:-50171}" --name "$CONTAINER_NAME" +"$BOOTH" --no-browser --keep-alive --daemon --variant base --port "${CB_PORT:-50171}" --name "$CONTAINER_NAME" # Wait for booth to be ready (up to 60 seconds) echo "Waiting for booth container to start..." diff --git a/examples/workspaces/kind-example/.cb-tests/test001-kind-cluster-on-host.sh b/examples/workspaces/kind-example/.cb-tests/test001-kind-cluster-on-host.sh index 452b4165..1f359d04 100755 --- a/examples/workspaces/kind-example/.cb-tests/test001-kind-cluster-on-host.sh +++ b/examples/workspaces/kind-example/.cb-tests/test001-kind-cluster-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -60,7 +66,7 @@ sleep 1 # Start booth in daemon mode echo "Starting booth with KinD..." -../../../codingbooth --no-browser --keep-alive --variant base --port "${CB_PORT:-50181}" --daemon --name "$CONTAINER_NAME" -p "" || true +"$BOOTH" --no-browser --keep-alive --variant base --port "${CB_PORT:-50181}" --daemon --name "$CONTAINER_NAME" -p "" || true # Wait for booth to be ready sleep 3 diff --git a/examples/workspaces/server-example-2/.cb-tests/test-on-host.sh b/examples/workspaces/server-example-2/.cb-tests/test-on-host.sh index 6f7e45b2..29c4fa8a 100755 --- a/examples/workspaces/server-example-2/.cb-tests/test-on-host.sh +++ b/examples/workspaces/server-example-2/.cb-tests/test-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -37,7 +43,7 @@ echo # Test 1: Start booth in daemon mode echo "Starting codingbooth in daemon mode..." -../../../codingbooth --no-browser --daemon > /dev/null 2>&1 || true +"$BOOTH" --no-browser --daemon > /dev/null 2>&1 || true sleep 2 # Check if booth container is running diff --git a/examples/workspaces/server-example-2/.cb-tests/test001-server-on-host.sh b/examples/workspaces/server-example-2/.cb-tests/test001-server-on-host.sh index a8706ac0..fa170031 100755 --- a/examples/workspaces/server-example-2/.cb-tests/test001-server-on-host.sh +++ b/examples/workspaces/server-example-2/.cb-tests/test001-server-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -42,7 +48,7 @@ sleep 1 # Start workspace in daemon mode with fixed port mapping echo "Starting codingbooth..." -../../../codingbooth --no-browser --variant base --port "${CB_PORT:-50301}" --daemon --name "$CONTAINER_NAME" -p "$SERVER_HOST_PORT":8080 || true +"$BOOTH" --no-browser --variant base --port "${CB_PORT:-50301}" --daemon --name "$CONTAINER_NAME" -p "$SERVER_HOST_PORT":8080 || true sleep 2 # Check if booth container is running diff --git a/examples/workspaces/server-example/.cb-tests/test-on-host.sh b/examples/workspaces/server-example/.cb-tests/test-on-host.sh index 6f7e45b2..29c4fa8a 100755 --- a/examples/workspaces/server-example/.cb-tests/test-on-host.sh +++ b/examples/workspaces/server-example/.cb-tests/test-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -37,7 +43,7 @@ echo # Test 1: Start booth in daemon mode echo "Starting codingbooth in daemon mode..." -../../../codingbooth --no-browser --daemon > /dev/null 2>&1 || true +"$BOOTH" --no-browser --daemon > /dev/null 2>&1 || true sleep 2 # Check if booth container is running diff --git a/examples/workspaces/server-example/.cb-tests/test001-server-on-host.sh b/examples/workspaces/server-example/.cb-tests/test001-server-on-host.sh index a8706ac0..fa170031 100755 --- a/examples/workspaces/server-example/.cb-tests/test001-server-on-host.sh +++ b/examples/workspaces/server-example/.cb-tests/test001-server-on-host.sh @@ -8,6 +8,12 @@ set -euo pipefail +# Locate the booth wrapper from this script's own location, so it works from any cwd. +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" +BOOTH="$REPO_ROOT/booth" +[ -x "$BOOTH" ] || BOOTH="$REPO_ROOT/codingbooth" +[ -x "$BOOTH" ] || { echo "booth wrapper not found under $REPO_ROOT" >&2; exit 1; } + cd "$(dirname "$0")/.." GREEN='\033[0;32m' @@ -42,7 +48,7 @@ sleep 1 # Start workspace in daemon mode with fixed port mapping echo "Starting codingbooth..." -../../../codingbooth --no-browser --variant base --port "${CB_PORT:-50301}" --daemon --name "$CONTAINER_NAME" -p "$SERVER_HOST_PORT":8080 || true +"$BOOTH" --no-browser --variant base --port "${CB_PORT:-50301}" --daemon --name "$CONTAINER_NAME" -p "$SERVER_HOST_PORT":8080 || true sleep 2 # Check if booth container is running diff --git a/examples/workspaces/zig-example/Justfile b/examples/workspaces/zig-example/Justfile index 96c3ed66..45706512 100644 --- a/examples/workspaces/zig-example/Justfile +++ b/examples/workspaces/zig-example/Justfile @@ -1,3 +1,7 @@ +# Keep Zig's cache off the bind mount: on Windows hosts, Zig's cache rename +# into a mounted .zig-cache fails with AccessDenied. +export ZIG_LOCAL_CACHE_DIR := env_var_or_default("ZIG_LOCAL_CACHE_DIR", "/tmp/zig-cache") + [private] default: @just --list diff --git a/tests/setups/test--dind-docker-config-helpers.sh b/tests/setups/test--dind-docker-config-helpers.sh new file mode 100644 index 00000000..5c2813e1 --- /dev/null +++ b/tests/setups/test--dind-docker-config-helpers.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# Copyright 2025-2026 : Nawa Manusitthipol +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. + +# ----------------------------------------------------------------------------- +# Unit test: dind startup drops host-only docker credential helpers +# +# Extracts the startup script embedded in dind--setup.sh and asserts it: +# - removes a credsStore whose docker-credential-* binary is absent +# (Docker Desktop's "desktop"), keeping auths and other keys +# - removes only the unresolvable credHelpers entries +# - leaves a config alone when every helper resolves +# - no-ops when there is no config +# No Docker / image build — hermetic host-side check (needs jq, like the image). +# ----------------------------------------------------------------------------- + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$SCRIPT_DIR" +source ../common--source.sh + +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +SETUP="$REPO_ROOT/variants/base/setups/dind--setup.sh" + +if ! command -v jq >/dev/null 2>&1; then + echo "SKIP: jq not installed on this host" + exit 0 +fi + +STARTUP_BODY=$(awk " + /^cat > \"\\\$\\{STARTUP_FILE\\}\" <<'STARTUP'\$/ { grab=1; next } + grab && /^STARTUP\$/ { exit } + grab { print } +" "$SETUP") + +if [[ -z "$STARTUP_BODY" ]]; then + echo "FAIL: could not extract STARTUP body from dind--setup.sh" + exit 1 +fi + +FAILED=0 + +# run_case NAME INPUT_JSON EXPECTED_JSON [helper names to stub on PATH...] +run_case() { + local name="$1" input="$2" expected="$3" + shift 3 + + local work + work=$(mktemp -d) + mkdir -p "$work/home/.docker" "$work/bin" + printf '%s\n' "$STARTUP_BODY" >"$work/startup.sh" + [[ -n "$input" ]] && printf '%s\n' "$input" >"$work/home/.docker/config.json" + for helper in "$@"; do + printf '#!/bin/sh\n' >"$work/bin/docker-credential-$helper" + chmod +x "$work/bin/docker-credential-$helper" + done + + if ! HOME="$work/home" PATH="$work/bin:$PATH" DOCKER_CONFIG= bash "$work/startup.sh" >/dev/null; then + echo "FAIL: $name — startup exited non-zero" + FAILED=$((FAILED + 1)) + rm -rf "$work" + return + fi + + if [[ -z "$input" ]]; then + if [[ -e "$work/home/.docker/config.json" ]]; then + echo "FAIL: $name — config should not have been created" + FAILED=$((FAILED + 1)) + else + echo "OK: $name" + fi + rm -rf "$work" + return + fi + + local got want + got=$(jq -S . "$work/home/.docker/config.json") + want=$(jq -S . <<<"$expected") + if [[ "$got" == "$want" ]]; then + echo "OK: $name" + else + echo "FAIL: $name" + echo " want: $want" + echo " got: $got" + FAILED=$((FAILED + 1)) + fi + rm -rf "$work" +} + +run_case "Docker Desktop credsStore removed" \ + '{"auths":{},"credsStore":"desktop","currentContext":"desktop-linux"}' \ + '{"auths":{},"currentContext":"desktop-linux"}' + +run_case "auths kept when credsStore removed" \ + '{"auths":{"ghcr.io":{"auth":"abc"}},"credsStore":"desktop"}' \ + '{"auths":{"ghcr.io":{"auth":"abc"}}}' + +run_case "only unresolvable credHelpers removed" \ + '{"credHelpers":{"gcr.io":"gcloud","ecr.example":"ecr-login"}}' \ + '{"credHelpers":{"gcr.io":"gcloud"}}' \ + gcloud + +run_case "empty credHelpers dropped" \ + '{"credsStore":"osxkeychain","credHelpers":{"gcr.io":"gcloud"}}' \ + '{}' + +run_case "resolvable helpers left alone" \ + '{"credsStore":"pass","credHelpers":{"gcr.io":"gcloud"}}' \ + '{"credsStore":"pass","credHelpers":{"gcr.io":"gcloud"}}' \ + pass gcloud + +run_case "no config is a no-op" "" "" + +if [[ "$FAILED" -eq 0 ]]; then + echo "All dind docker-config helper checks passed." + exit 0 +fi +echo "$FAILED dind docker-config helper check(s) failed." +exit 1 diff --git a/variants/base/setups/dind--setup.sh b/variants/base/setups/dind--setup.sh index 3f2f75b3..c48d971c 100755 --- a/variants/base/setups/dind--setup.sh +++ b/variants/base/setups/dind--setup.sh @@ -58,3 +58,50 @@ wait "$SOCAT_PID" 2>/dev/null || true fi EOF sudo chmod 755 "${STOPPER_FILE}" + + +# ---- startup script: drop host-only credential helpers from docker config ---- +# Numbered before the autostart segments (floci, appwrite, ...) that pull images. +STARTUP_FILE="/usr/share/startup.d/40-cb-dind--startup.sh" +mkdir -p "$(dirname "${STARTUP_FILE}")" +cat > "${STARTUP_FILE}" <<'STARTUP' +#!/usr/bin/env bash +set -uo pipefail + +# dind startup script +# Docker Desktop hosts write "credsStore": "desktop" (and credHelpers entries) +# into ~/.docker/config.json. The docker-config extension seeds that file into +# the booth, where those helper binaries do not exist, so every `docker pull` +# fails with "docker-credential-desktop: executable file not found". Drop the +# helper references that cannot be resolved here; plain "auths" entries stay. + +CONFIG="${DOCKER_CONFIG:-$HOME/.docker}/config.json" +[[ -f "$CONFIG" ]] || exit 0 +command -v jq >/dev/null 2>&1 || exit 0 + +helpers=$(jq -r '[.credsStore // empty] + [(.credHelpers // {})[]] | unique[]' "$CONFIG" 2>/dev/null) || exit 0 + +missing=() +while IFS= read -r helper; do + [[ -z "$helper" ]] && continue + command -v "docker-credential-$helper" >/dev/null 2>&1 || missing+=("$helper") +done <<< "$helpers" +[[ ${#missing[@]} -eq 0 ]] && exit 0 + +missing_json=$(printf '%s\n' "${missing[@]}" | jq -R . | jq -s .) +tmp="$CONFIG.cb-tmp.$$" +if jq --argjson missing "$missing_json" ' + (if (.credsStore // null) as $s | $s != null and ($missing | index($s)) + then del(.credsStore) else . end) + | (if .credHelpers + then .credHelpers |= with_entries(select(.value as $v | ($missing | index($v)) | not)) + | (if .credHelpers == {} then del(.credHelpers) else . end) + else . end) + ' "$CONFIG" > "$tmp" 2>/dev/null && mv -f "$tmp" "$CONFIG" 2>/dev/null; then + echo "Removed unavailable docker credential helper(s) from $CONFIG: ${missing[*]}" +else + rm -f "$tmp" +fi +exit 0 +STARTUP +chmod 755 "${STARTUP_FILE}"