97 lines
4.0 KiB
Bash
Executable File
97 lines
4.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Smoke-test node-agent.
|
|
#
|
|
# Two things are verified: every tool the README advertises is present and runnable,
|
|
# and the image behaves under the restrictions it is actually deployed with
|
|
# (non-root, read-only root filesystem, all capabilities dropped).
|
|
#
|
|
# Usage: test.sh [image-ref]
|
|
set -euo pipefail
|
|
|
|
REF="${1:-node-agent:dev}"
|
|
echo "==> smoke-testing ${REF}"
|
|
|
|
# Deliberately mirrors the ToolHive securityContext for the shell MCP server:
|
|
# runAsUser 1000, readOnlyRootFilesystem, capabilities drop ALL.
|
|
docker run --rm --interactive \
|
|
--user 1000:1000 \
|
|
--read-only \
|
|
--tmpfs /tmp:rw,size=64m \
|
|
--cap-drop ALL \
|
|
--env HOME=/tmp \
|
|
"$REF" bash -s <<'INNER'
|
|
set -uo pipefail
|
|
fail=0
|
|
|
|
ok() { printf ' \033[32mok\033[0m %s\n' "$1"; }
|
|
bad() { printf ' \033[31mFAIL\033[0m %s\n' "$1"; fail=1; }
|
|
have() { command -v "$1" >/dev/null 2>&1 && ok "$1" || bad "$1 (not on PATH)"; }
|
|
works(){ local d=$1; shift; if "$@" >/dev/null 2>&1; then ok "$d"; else bad "$d"; fi; }
|
|
|
|
# Only the first line is checked, because a BusyBox applet's later output can
|
|
# mention the GNU GPL and would false-positive. `sed -n 1p` rather than `head -1`
|
|
# so the reader consumes all input: head exits early, which under `pipefail`
|
|
# SIGPIPEs the producer and fails the pipeline nondeterministically.
|
|
gnu() {
|
|
local first
|
|
first=$("$1" --version 2>/dev/null | sed -n '1p')
|
|
case $first in
|
|
*GNU*) ok "$1 is GNU" ;;
|
|
*) bad "$1 is not GNU (${first:-no output})" ;;
|
|
esac
|
|
}
|
|
|
|
echo "-- present on PATH"
|
|
for t in bash sh curl wget jq yq yamllint helm kubectl git git-lfs ssh scp dig nslookup \
|
|
host nc socat rsync ping rg fd tar gzip xz zip unzip less file patch tree make \
|
|
ps top free tini su-exec node npm npx openssl base64 env xargs; do
|
|
have "$t"
|
|
done
|
|
|
|
echo "-- GNU userland, not busybox (flag compatibility matters for agent scripts)"
|
|
for t in grep sed awk find sort diff; do gnu "$t"; done
|
|
|
|
echo "-- functional"
|
|
works 'jq filters' bash -c 'echo "{\"a\":1}" | jq -e ".a == 1"'
|
|
works 'yq filters' bash -c 'printf "a: 1\n" | yq -e ".a == 1"'
|
|
works 'helm runs' helm version --short
|
|
works 'helm template' bash -c 'helm create /tmp/c >/dev/null && helm template /tmp/c >/dev/null'
|
|
works 'kubectl client' kubectl version --client
|
|
works 'git init' bash -c 'git init -q /tmp/r && git -C /tmp/r status --short'
|
|
works 'rg searches' bash -c 'printf "needle\n" >/tmp/h && rg -q needle /tmp/h'
|
|
works 'fd finds' bash -c 'fd -1 . /tmp >/dev/null'
|
|
works 'dig runs' dig -v
|
|
works 'openssl runs' openssl version
|
|
works 'node runs' node -e 'process.exit(0)'
|
|
works 'yamllint flags bad' bash -c '! printf "a: [\n" | yamllint - >/dev/null 2>&1'
|
|
works 'yamllint passes ok' bash -c 'printf "a: 1\n" | yamllint -d relaxed -'
|
|
|
|
echo "-- deployment contract"
|
|
[ "$(id -u)" = 1000 ] && ok 'runs as uid 1000' || bad "runs as uid $(id -u), want 1000"
|
|
touch /tmp/writable 2>/dev/null && ok '/tmp is writable' || bad '/tmp is not writable'
|
|
if touch /should-not-work 2>/dev/null; then
|
|
bad 'root filesystem is writable (expected read-only)'
|
|
else
|
|
ok 'root filesystem is read-only'
|
|
fi
|
|
# Pagers must be disabled or git/kubectl/helm hang with no TTY attached.
|
|
[ "${PAGER:-}" = cat ] && ok 'PAGER=cat' || bad "PAGER=${PAGER:-unset}, want cat"
|
|
[ "${GIT_TERMINAL_PROMPT:-}" = 0 ] && ok 'GIT_TERMINAL_PROMPT=0' \
|
|
|| bad 'GIT_TERMINAL_PROMPT not 0'
|
|
|
|
echo
|
|
[ "$fail" = 0 ] && echo "all checks passed" || echo "FAILURES above"
|
|
exit "$fail"
|
|
INNER
|
|
|
|
# The default CMD should land in a usable shell rather than the node REPL. Pass no
|
|
# arguments so the image's own CMD runs, and feed the script on stdin — the base
|
|
# image's docker-entrypoint.sh rewrites a leading "-c" into a `node` invocation.
|
|
echo "==> checking default CMD"
|
|
if [ "$(echo 'echo shell-ok' | docker run --rm --interactive "$REF")" = shell-ok ]; then
|
|
echo " ok default CMD is bash"
|
|
else
|
|
echo " FAIL default CMD is not bash"
|
|
exit 1
|
|
fi
|