#!/bin/sh set -eu cd "$(dirname "$0")/.." tmp=$(mktemp -d) trap 'rm -rf "$tmp"' EXIT HUP INT TERM fake="$tmp/docker" log="$tmp/docker.log" cat >"$fake" <<'SH' #!/bin/sh set -eu invocation=$* test "${1:-}" = compose shift env_file= while [ "$#" -gt 0 ]; do case "$1" in --env-file) [ "$#" -ge 2 ] || exit 64 env_file=$2 shift 2 ;; --env-file=*) env_file=${1#--env-file=} shift ;; *) shift ;; esac done [ -n "$env_file" ] && [ -f "$env_file" ] || { echo "fake docker rejected missing env file: $env_file" >&2 exit 64 } printf '%s:%s\n' "${THT_VECTOR_BOOTSTRAP_USER:-unset}" "$invocation" >>"$FAKE_DOCKER_LOG" exit "${FAKE_DOCKER_EXIT:-0}" SH chmod 0755 "$fake" printf '%s' old-password >"$tmp/old" printf '%s' "new-'quoted-\$-password" >"$tmp/new" cp "$tmp/old" "$tmp/original" printf 'invalid password\n' >"$tmp/whitespace" printf '%s\n' 'THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/thoth-workspaces.git' \ >"$tmp/operator.env" printf '%s\n' 'THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/unsafe.git' \ >"$tmp/unsafe.env" ln -s "$tmp/operator.env" "$tmp/operator-link.env" chmod 0600 "$tmp/old" "$tmp/new" "$tmp/original" "$tmp/whitespace" "$tmp/operator.env" chmod 0660 "$tmp/unsafe.env" if PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" \ ./scripts/vector-rotate-bootstrap-password.sh "$tmp/old" "$tmp/new" \ >"$tmp/out" 2>"$tmp/err"; then echo "rotation silently assumed an operator env file" >&2 exit 1 fi grep -q 'requires --env-file or THT_VECTOR_OPERATOR_ENV_FILE' "$tmp/err" test ! -s "$log" if PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" \ ./scripts/vector-rotate-bootstrap-password.sh --env-file "$tmp/missing.env" \ "$tmp/old" "$tmp/new" >"$tmp/out" 2>"$tmp/err"; then echo "rotation accepted a nonexistent operator env file" >&2 exit 1 fi grep -q 'operator env must be a readable regular file' "$tmp/err" test ! -s "$log" for unsafe_env in "$tmp/unsafe.env" "$tmp/operator-link.env"; do if PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" \ ./scripts/vector-rotate-bootstrap-password.sh --env-file "$unsafe_env" \ "$tmp/old" "$tmp/new" >"$tmp/out" 2>"$tmp/err"; then echo "rotation accepted unsafe operator env file $unsafe_env" >&2 exit 1 fi test ! -s "$log" done : >"$log" if PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" THT_VECTOR_BOOTSTRAP_USER=custom_admin \ ./scripts/vector-rotate-bootstrap-password.sh --env-file "$tmp/operator.env" \ "$tmp/old" "$tmp/whitespace" \ >"$tmp/out" 2>"$tmp/err"; then echo "rotation accepted a whitespace-containing secret" >&2 exit 1 fi cmp "$tmp/old" "$tmp/original" test ! -s "$log" if find "$tmp" -name 'old.rotate.*' -print | grep -q .; then echo "rotation staged a deployment file before secret validation" >&2 exit 1 fi if PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" FAKE_DOCKER_EXIT=1 \ ./scripts/vector-rotate-bootstrap-password.sh --env-file "$tmp/operator.env" \ "$tmp/old" "$tmp/new" \ >"$tmp/out" 2>"$tmp/err"; then echo "rotation unexpectedly succeeded when database verification failed" >&2 exit 1 fi cmp "$tmp/old" "$tmp/original" : >"$log" PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" THT_VECTOR_BOOTSTRAP_USER=custom_admin \ ./scripts/vector-rotate-bootstrap-password.sh --env-file "$tmp/operator.env" \ "$tmp/old" "$tmp/new" \ >"$tmp/out" 2>"$tmp/err" cmp "$tmp/old" "$tmp/new" grep -q -- "--env-file $tmp/operator.env" "$log" grep -q '/run/secrets/bootstrap-old:ro' "$log" grep -q '/run/secrets/bootstrap-new:ro' "$log" grep -q '^custom_admin:' "$log" grep -q 'atomically replaced only after verified database login' "$tmp/out" printf '%s' old-password >"$tmp/old" : >"$log" PATH="$tmp:$PATH" FAKE_DOCKER_LOG="$log" \ THT_VECTOR_OPERATOR_ENV_FILE="$tmp/operator.env" \ ./scripts/vector-rotate-bootstrap-password.sh "$tmp/old" "$tmp/new" \ >"$tmp/out" 2>"$tmp/err" grep -q -- "--env-file $tmp/operator.env" "$log" echo "bootstrap rotation env propagation, validation, ordering, and failure contracts passed."