From 6c67390d52a022f7af3ee7c8588f6a6096faf62b Mon Sep 17 00:00:00 2001 From: Rogee Date: Tue, 25 Aug 2026 00:40:20 +0800 Subject: [PATCH] HH-636: run container smoke test in CI (#5) --- .github/workflows/docker.yml | 3 ++ Dockerfile | 16 +++++---- tests/container-smoke.sh | 70 ++++++++++++++++-------------------- tests/workflow-contract.sh | 1 + 4 files changed, 43 insertions(+), 47 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8ff6448..6c45b70 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -38,6 +38,9 @@ jobs: - name: Run tests run: ./scripts/test.sh + - name: Run container smoke test + run: ./tests/container-smoke.sh + build: name: Build and publish needs: test diff --git a/Dockerfile b/Dockerfile index daa8e5d..a8eee6d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,11 +17,12 @@ FROM alpine:${ALPINE_VERSION} AS release-assets ARG TARGETARCH ARG SSCLASH_VERSION=v6.1.0 ARG MIHOMO_VERSION=v1.19.30 -ARG MIHOMO_SHA256_AMD64=cf06ce2c7d1421bdbda14ee4a5b6046672dc35ebf8eecd8e77504ec3c0ed9a84 +ARG MIHOMO_SHA256_AMD64=cbe553d0319a414bd3a372c5976a252155b2c4882b66bce88a4d6bba9571a553 ARG MIHOMO_SHA256_ARM64=58896873736d28628f66de3677c8654fa0f180662523148e136cff4f6e890069 WORKDIR /assets RUN apk add --no-cache ca-certificates curl gzip -RUN case "${TARGETARCH}" in \ +RUN set -eu; \ + case "${TARGETARCH}" in \ amd64|arm64) ;; \ *) echo "unsupported TARGETARCH=${TARGETARCH}; supported: amd64, arm64" >&2; exit 1 ;; \ esac; \ @@ -35,11 +36,11 @@ RUN case "${TARGETARCH}" in \ test -n "${expected}"; \ printf '%s %s\n' "${expected}" ssclash | sha256sum -c -; \ chmod 0755 ssclash -RUN case "${TARGETARCH}" in \ - amd64) mihomo_sha256="${MIHOMO_SHA256_AMD64}" ;; \ - arm64) mihomo_sha256="${MIHOMO_SHA256_ARM64}" ;; \ +RUN set -eu; \ + case "${TARGETARCH}" in \ + amd64) asset="mihomo-linux-amd64-v1-${MIHOMO_VERSION}.gz"; mihomo_sha256="${MIHOMO_SHA256_AMD64}" ;; \ + arm64) asset="mihomo-linux-arm64-${MIHOMO_VERSION}.gz"; mihomo_sha256="${MIHOMO_SHA256_ARM64}" ;; \ esac; \ - asset="mihomo-linux-${TARGETARCH}-${MIHOMO_VERSION}.gz"; \ curl --fail --show-error --silent --location --retry 3 \ --output mihomo.gz \ "https://github.com/MetaCubeX/mihomo/releases/download/${MIHOMO_VERSION}/${asset}"; \ @@ -51,7 +52,8 @@ FROM alpine:${ALPINE_VERSION} AS acl4ssr-assets ARG ACL4SSR_REF=6e27259b8625e360699c014f98f978ee7408c644 ARG ACL4SSR_SHA256=72229e2f0a38fc9776720a20dd4ecb44fdd0b0704bbf1f5141732562a237bff2 RUN apk add --no-cache ca-certificates curl -RUN curl --fail --show-error --silent --location --retry 3 \ +RUN set -eu; \ + curl --fail --show-error --silent --location --retry 3 \ --output /tmp/acl4ssr.tar.gz \ "https://github.com/ACL4SSR/ACL4SSR/archive/${ACL4SSR_REF}.tar.gz"; \ printf '%s %s\n' "${ACL4SSR_SHA256}" /tmp/acl4ssr.tar.gz | sha256sum -c -; \ diff --git a/tests/container-smoke.sh b/tests/container-smoke.sh index 484b561..2079fa7 100755 --- a/tests/container-smoke.sh +++ b/tests/container-smoke.sh @@ -8,8 +8,6 @@ unconfigured="mohomo-docker-unconfigured-${suffix}" provider="mohomo-provider-smoke-${suffix}" network="mohomo-network-smoke-${suffix}" volume="mohomo-volume-smoke-${suffix}" -provider_dir="" -cookie="" secret="container-smoke-secret" admin_password="container-smoke-admin-password" @@ -22,8 +20,6 @@ cleanup() { docker container rm --force "$container" "$unconfigured" "$provider" >/dev/null 2>&1 || true docker volume rm "$volume" >/dev/null 2>&1 || true docker network rm "$network" >/dev/null 2>&1 || true - [ -z "$provider_dir" ] || rm -rf "$provider_dir" - [ -z "$cookie" ] || rm -f "$cookie" } trap cleanup EXIT INT TERM @@ -53,27 +49,34 @@ assert_published_ports() { assert_web_login() { web_port=$1 - : > "$cookie" - setup_redirect=$(curl --silent --show-error --output /dev/null \ - --write-out '%{http_code} %{redirect_url}' \ - "http://127.0.0.1:${web_port}/setup") - if [ "$setup_redirect" != "303 http://127.0.0.1:${web_port}/login" ]; then - echo "configured Web UI exposed setup: ${setup_redirect}" >&2 - exit 1 - fi - login_html=$(curl --fail --silent --show-error --cookie-jar "$cookie" \ - "http://127.0.0.1:${web_port}/login") - login_csrf=$(printf '%s' "$login_html" | sed -n 's/.*name="csrf" value="\([^"]*\)".*/\1/p' | head -1) - test -n "$login_csrf" - curl --fail --silent --show-error \ - --cookie "$cookie" \ - --cookie-jar "$cookie" \ - --request POST \ - --data-urlencode "csrf=${login_csrf}" \ - --data-urlencode "password=${admin_password}" \ - "http://127.0.0.1:${web_port}/login" >/dev/null - curl --fail --silent --show-error --cookie "$cookie" \ - "http://127.0.0.1:${web_port}/config" | grep -F 'csrf-token' >/dev/null + docker run --rm --network host \ + --env "WEB_PORT=${web_port}" \ + --env "ADMIN_PASSWORD=${admin_password}" \ + --entrypoint /bin/sh \ + "$image" -c ' + set -eu + cookie=$(mktemp) + setup_redirect=$(curl --silent --show-error --output /dev/null \ + --write-out "%{http_code} %{redirect_url}" \ + "http://127.0.0.1:${WEB_PORT}/setup") + if [ "$setup_redirect" != "303 http://127.0.0.1:${WEB_PORT}/login" ]; then + echo "configured Web UI exposed setup: ${setup_redirect}" >&2 + exit 1 + fi + login_html=$(curl --fail --silent --show-error --cookie-jar "$cookie" \ + "http://127.0.0.1:${WEB_PORT}/login") + login_csrf=$(printf "%s" "$login_html" | sed -n "s/.*name=\"csrf\" value=\"\([^\"]*\)\".*/\1/p" | head -1) + test -n "$login_csrf" + curl --fail --silent --show-error \ + --cookie "$cookie" \ + --cookie-jar "$cookie" \ + --request POST \ + --data-urlencode "csrf=${login_csrf}" \ + --data-urlencode "password=${ADMIN_PASSWORD}" \ + "http://127.0.0.1:${WEB_PORT}/login" >/dev/null + curl --fail --silent --show-error --cookie "$cookie" \ + "http://127.0.0.1:${WEB_PORT}/config" | grep -F csrf-token >/dev/null + ' } default_compose=$(SUBSCRIPTION_URL=https://subscription.example.invalid/mihomo docker compose config) @@ -101,27 +104,15 @@ docker run --rm --network none --entrypoint /bin/sh "$image" -c ' /usr/local/lib/ssclash/clash -t -d "$runtime" -f "$runtime/config.yaml" ' >/dev/null -provider_dir=$(mktemp -d) -printf '%s\n' \ - 'proxies:' \ - ' - name: smoke-node' \ - ' type: socks5' \ - ' server: 127.0.0.1' \ - ' port: 9' \ - > "$provider_dir/provider.yaml" -chmod 0755 "$provider_dir" -chmod 0644 "$provider_dir/provider.yaml" - docker network create "$network" >/dev/null docker volume create "$volume" >/dev/null docker run --detach --rm \ --name "$provider" \ --network "$network" \ - --volume "$provider_dir:/srv:ro" \ --entrypoint /bin/sh \ - "$image" -c 'while :; do { printf "HTTP/1.1 200 OK\r\nContent-Type: text/yaml\r\nConnection: close\r\n\r\n"; cat /srv/provider.yaml; } | nc -l -p 8080; done' >/dev/null + "$image" -c 'while :; do printf "HTTP/1.1 200 OK\r\nContent-Type: text/yaml\r\nConnection: close\r\n\r\nproxies:\n - name: smoke-node\n type: socks5\n server: 127.0.0.1\n port: 9\n" | nc -l -p 8080; done' >/dev/null attempt=0 -until docker exec "$provider" wget -qO- http://127.0.0.1:8080/provider.yaml >/dev/null; do +until docker exec "$provider" wget -qO- http://127.0.0.1:8080/provider.yaml | grep -F 'name: smoke-node' >/dev/null; do attempt=$((attempt + 1)) if [ "$attempt" -ge 10 ]; then echo "subscription fixture did not become ready" >&2 @@ -164,7 +155,6 @@ if docker logs "$unconfigured" 2>&1 | grep -F 'web UI listening' >/dev/null; the exit 1 fi docker container rm "$unconfigured" >/dev/null -cookie=$(mktemp) docker run --detach \ --name "$container" \ diff --git a/tests/workflow-contract.sh b/tests/workflow-contract.sh index 01594ca..9d7df2f 100755 --- a/tests/workflow-contract.sh +++ b/tests/workflow-contract.sh @@ -13,6 +13,7 @@ grep -F 'packages: write' "$workflow" >/dev/null grep -F 'ghcr.io/${{ github.repository }}' "$workflow" >/dev/null grep -F 'platforms: linux/amd64' "$workflow" >/dev/null grep -F 'needs: test' "$workflow" >/dev/null +grep -F 'run: ./tests/container-smoke.sh' "$workflow" >/dev/null grep -F 'cache-to: type=gha,mode=max,ignore-error=true' "$workflow" >/dev/null # Match the GitHub expression literally. # shellcheck disable=SC2016