diff options
| author | Leonard Kugis <leonard@kug.is> | 2026-01-31 14:08:20 +0100 |
|---|---|---|
| committer | Leonard Kugis <leonard@kug.is> | 2026-01-31 14:08:20 +0100 |
| commit | 94000f6b6d07b31151deccc4e3e1fdccf5b5c487 (patch) | |
| tree | c0d5450d5d445fc675d899d72de2957d5e6e289b | |
| parent | 4742f1125021f6bc1a2631c6e54cf6365f9d37f6 (diff) | |
| download | llm-functions-docker-94000f6b6d07b31151deccc4e3e1fdccf5b5c487.tar.gz | |
Added docker scripts
| -rw-r--r-- | tools/docker_exec.sh | 27 | ||||
| -rw-r--r-- | tools/docker_start.sh | 70 | ||||
| -rw-r--r-- | tools/docker_stop.sh | 18 |
3 files changed, 115 insertions, 0 deletions
diff --git a/tools/docker_exec.sh b/tools/docker_exec.sh new file mode 100644 index 0000000..66f79bc --- /dev/null +++ b/tools/docker_exec.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +# @describe Execute a shell command inside a sandbox container. +# @option --container! Container name/id to execute in. +# @option --command! Shell command to run (executed via sh -lc inside container). +# @option --timeout_sec Timeout in seconds. Default: 60 + +main() { + local c="${argc_container}" + local cmd="${argc_command}" + local t="${argc_timeout_sec:-60}" + + if ! docker ps --format '{{.Names}}' | grep -qx "$c"; then + echo "ERROR: container not running: $c" >> "$LLM_OUTPUT" + exit 2 + fi + + local out + local rc=0 + out="$(timeout "${t}" docker exec "$c" sh -lc "$cmd" 2>&1)" || rc=$? + + printf '{"exit_code":%d,"output":%s}\n' "$rc" "$(python -c 'import json,sys; print(json.dumps(sys.stdin.read()))' <<<"$out")" >> "$LLM_OUTPUT" +} + +eval "$(argc --argc-eval "$0" "$@")" + diff --git a/tools/docker_start.sh b/tools/docker_start.sh new file mode 100644 index 0000000..cec5808 --- /dev/null +++ b/tools/docker_start.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +# @describe Start (or reuse) a sandbox Docker container with a bind-mounted workspace. +# @option --workspace! Host path to mount into the container at /work (must be under $AICHAT_SANDBOX_BASE). +# @option --image Docker image to use. Default: aichat-docker:latest +# @option --name Optional explicit container name. Default: auto-generated. +# @option --network Enable network access (true/false). Default: true +# @option --ttl_minutes Optional TTL label for cleanup tooling. Default: 0 (no TTL) + +main() { + local base="${AICHAT_SANDBOX_BASE:-$HOME/aichat-workspaces}" + local image="${argc_image:-aichat-docker:latest}" + local net="${argc_network:-true}" + local ttl="${argc_ttl_minutes:-0}" + + mkdir -p "$base" + + local ws + ws="$(realpath -m "${argc_workspace}")" + + local base_real + base_real="$(realpath -m "$base")" + case "$ws" in + "$base_real"/*) ;; + *) + echo "ERROR: workspace must be under $base_real (got $ws)" >> "$LLM_OUTPUT" + exit 2 + ;; + esac + + mkdir -p "$ws" + + local name="${argc_name:-aichat-sbx-$(date +%s)-$RANDOM}" + + if docker ps -a --format '{{.Names}}' | grep -qx "$name"; then + printf '{"container":"%s","workspace":"%s","status":"already-exists"}\n' "$name" "$ws" >> "$LLM_OUTPUT" + return 0 + fi + + local net_arg=() + if [[ "$net" == "false" ]]; then + net_arg+=(--network none) + fi + + local uid gid + uid="$(id -u)" + gid="$(id -g)" + + docker run -d --rm \ + --name "$name" \ + -u "${uid}:${gid}" \ + -w /work \ + -v "${ws}:/work:rw" \ + --cap-drop=ALL \ + --security-opt=no-new-privileges \ + --pids-limit 256 \ + --memory 2g \ + --cpus 2 \ + "${net_arg[@]}" \ + --label "aichat.sandbox=true" \ + --label "aichat.ttl_minutes=${ttl}" \ + "$image" \ + sh -lc 'sleep infinity' >/dev/null + + printf '{"container":"%s","workspace":"%s","status":"started"}\n' "$name" "$ws" >> "$LLM_OUTPUT" +} + +eval "$(argc --argc-eval "$0" "$@")" + diff --git a/tools/docker_stop.sh b/tools/docker_stop.sh new file mode 100644 index 0000000..780a346 --- /dev/null +++ b/tools/docker_stop.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +# @describe Stop a sandbox container (it will be removed if started with --rm). +# @option --container! Container name/id to stop. + +main() { + local c="${argc_container}" + if docker ps --format '{{.Names}}' | grep -qx "$c"; then + docker stop "$c" >/dev/null + printf '{"container":"%s","status":"stopped"}\n' "$c" >> "$LLM_OUTPUT" + else + printf '{"container":"%s","status":"not-running"}\n' "$c" >> "$LLM_OUTPUT" + fi +} + +eval "$(argc --argc-eval "$0" "$@")" + |
