Files
gpustack-all-lofyer/scripts/verify-image
T
lofyerandfactory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> 004d18db92 feat: workspace tooling for the MesaStack fork
Add one-shot scripts driving both forks from the workspace root:

- build-image:   frontend build + thin-overlay image build + verification
- verify-image:  static and runtime smoke tests (brand, API key prefix,
                 login, real key creation), always cleans up its container
- sync-upstream: bump both forks to a new upstream release, cutting fresh
                 v<version>-lofyer branches and replaying fork-only commits
- bootstrap:     clone the two forks into place after cloning this repo

Fork-only commit detection deliberately goes beyond 'git log --cherry-pick
--right-only', which re-replays upstream commits that were rebased or
squashed into the new release; commits contained by any upstream ref or tag
are dropped instead.

The forks stay as separate repositories rather than submodules so each keeps
a clean upstream history to rebase onto new releases.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-07-27 09:16:05 +08:00

154 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# verify-image: smoke test a built MesaStack image.
#
# Checks, in order:
# 1. static - gpustack version, API_KEY_PREFIX, UI assets carry our brand
# and no leftover upstream brand in index.html
# 2. runtime - boots the server, confirms / serves the MesaStack title,
# logs in and creates an API key to prove the mesastack_ prefix
# is live end to end, and that old gpustack_ keys are rejected
#
# Usage:
# scripts/verify-image # verify ${NAMESPACE}/${REPOSITORY}:<workspace version>
# IMAGE=mesastack/gpustack:v2.2.1 scripts/verify-image
# scripts/verify-image --static-only # skip booting a container
#
set -o errexit
set -o nounset
set -o pipefail
source "$(dirname "${BASH_SOURCE[0]}")/lib/common.sh"
STATIC_ONLY=0
while [[ $# -gt 0 ]]; do
case "${1}" in
--static-only) STATIC_ONLY=1 ;;
-h|--help) sed -n '2,18p' "${0}"; exit 0 ;;
*) fail "unknown argument: ${1}" ;;
esac
shift
done
require_cmd docker curl python3
if [[ -z "${IMAGE:-}" ]]; then
require_repos
VERSION="$(resolve_workspace_version)"
IMAGE="${NAMESPACE}/${REPOSITORY}:${TAG:-${VERSION}}"
fi
SMOKE_PORT="${SMOKE_PORT:-18080}"
CONTAINER="${CONTAINER:-mesastack-verify}"
SITE_PACKAGES="/usr/local/lib/python3.11/dist-packages"
BRAND="${BRAND:-MesaStack}"
EXPECTED_PREFIX="${EXPECTED_PREFIX:-mesastack}"
docker image inspect "${IMAGE}" >/dev/null 2>&1 || fail "image not found locally: ${IMAGE}"
log "verifying ${IMAGE}"
failed=0
check() {
local label="${1}"; shift
if "$@" >/dev/null 2>&1; then
echo -e " \033[1;32mPASS\033[0m ${label}"
else
echo -e " \033[1;31mFAIL\033[0m ${label}"
failed=1
fi
}
# ---------- 1. Static checks ----------
step "Static checks"
docker run --rm --entrypoint bash "${IMAGE}" -c "
set -e
echo \"version: \$(gpustack version)\"
echo \"prefix : \$(python3 -c 'from gpustack.security import API_KEY_PREFIX; print(API_KEY_PREFIX)')\"
" || fail "image failed to report version/prefix"
check "API_KEY_PREFIX == ${EXPECTED_PREFIX}" \
docker run --rm --entrypoint python3 "${IMAGE}" -c \
"from gpustack.security import API_KEY_PREFIX as p; assert p == '${EXPECTED_PREFIX}', p"
check "old gpustack_ keys rejected" \
docker run --rm --entrypoint python3 "${IMAGE}" -c \
"from gpustack.security import is_valid_format as v; assert not v('gpustack_aaaa_bbbb')[0]"
check "masked value uses ${EXPECTED_PREFIX}_" \
docker run --rm --entrypoint python3 "${IMAGE}" -c \
"from gpustack.utils.api_keys import get_masked_api_key_value as m; assert m('abcd1234') == '${EXPECTED_PREFIX}_abcd***', m('abcd1234')"
check "UI index.html present" \
docker run --rm --entrypoint test "${IMAGE}" -f "${SITE_PACKAGES}/gpustack/ui/index.html"
check "UI carries ${BRAND} brand" \
docker run --rm --entrypoint grep "${IMAGE}" -q "${BRAND}" "${SITE_PACKAGES}/gpustack/ui/index.html"
check "no upstream GPUStack brand in UI index.html" \
docker run --rm --entrypoint bash "${IMAGE}" -c \
"! grep -q 'GPUStack' ${SITE_PACKAGES}/gpustack/ui/index.html"
if [[ "${STATIC_ONLY}" == "1" ]]; then
step "Result"
[[ "${failed}" == "0" ]] && { log "static checks passed"; exit 0; } || fail "static checks failed"
fi
# ---------- 2. Runtime checks ----------
step "Runtime checks (booting ${CONTAINER} on :${SMOKE_PORT})"
cleanup() {
docker rm -f "${CONTAINER}" >/dev/null 2>&1 || true
rm -f "${COOKIES:-/dev/null}" 2>/dev/null || true
}
trap cleanup EXIT
docker rm -f "${CONTAINER}" >/dev/null 2>&1 || true
docker run -d --name "${CONTAINER}" -p "${SMOKE_PORT}:80" "${IMAGE}" --disable-worker >/dev/null \
|| fail "failed to start container"
BASE="http://127.0.0.1:${SMOKE_PORT}"
log "waiting for server to become ready"
ready=0
for _ in $(seq 1 60); do
if curl -sS -m 5 -o /dev/null "${BASE}/" 2>/dev/null; then ready=1; break; fi
if ! docker ps --filter "name=${CONTAINER}" --format '{{.ID}}' | grep -q .; then
docker logs "${CONTAINER}" 2>&1 | tail -20
fail "container exited during startup"
fi
sleep 5
done
[[ "${ready}" == "1" ]] || { docker logs "${CONTAINER}" 2>&1 | tail -20; fail "server did not become ready"; }
check "/ serves ${BRAND} title" \
bash -c "curl -sS -m 15 '${BASE}/' | grep -q '<title>${BRAND}</title>'"
COOKIES="$(mktemp)"
PASSWORD="$(docker exec "${CONTAINER}" cat /var/lib/gpustack/initial_admin_password 2>/dev/null || echo "")"
if [[ -z "${PASSWORD}" ]]; then
warn "bootstrap password not found; skipping API key check"
else
login_status="$(curl -sS -c "${COOKIES}" -m 20 -o /dev/null -w '%{http_code}' \
-X POST "${BASE}/auth/login" \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode "username=admin" \
--data-urlencode "password=${PASSWORD}" || echo "000")"
check "admin login succeeds" test "${login_status}" = "200"
if [[ "${login_status}" == "200" ]]; then
key_value="$(curl -sS -b "${COOKIES}" -m 20 -X POST "${BASE}/v2/api-keys" \
-H 'Content-Type: application/json' \
-d '{"name":"verify-image","description":"prefix check"}' \
| python3 -c 'import json,sys; print(json.load(sys.stdin).get("value",""))' 2>/dev/null || echo "")"
log "generated key: ${key_value%%_*}_<redacted>"
check "generated key uses ${EXPECTED_PREFIX}_ prefix" \
bash -c "[[ '${key_value}' == ${EXPECTED_PREFIX}_* ]]"
fi
fi
step "Result"
if [[ "${failed}" == "0" ]]; then
log "all checks passed for ${IMAGE}"
else
fail "one or more checks failed for ${IMAGE}"
fi