fix(deploy): validate HK sub-path runtime

Signed-off-by: ylhu16 <ylhu16@iflytek.com>
This commit is contained in:
ylhu16 2026-08-06 15:38:25 +08:00
parent 091e676ca5
commit 79be943f0f
5 changed files with 148 additions and 19 deletions

View file

@ -17,6 +17,16 @@ on:
required: false
default: manual-test-hk
type: string
public_url:
description: "Public URL configured on the HK runtime"
required: false
default: https://skill.xf-yun.com.cn
type: string
web_base_path:
description: "Optional Web UI base path for HK runtime, for example /skillhub/"
required: false
default: ""
type: string
concurrency:
group: pr-batch-test-runtime
@ -145,7 +155,9 @@ jobs:
--immutable-tag "${{ steps.batch.outputs.immutable_tag }}" \
--merged-sha "${{ steps.batch.outputs.merged_sha }}" \
--pr-csv "${{ steps.batch.outputs.pr_csv }}" \
--run-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
--run-url "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" \
--public-url "${{ inputs.public_url }}" \
--web-base-path "${{ inputs.web_base_path }}"
- name: Publish final summary
run: |
@ -153,6 +165,8 @@ jobs:
echo "### HK manual test runtime updated"
echo
echo "- URL: \`https://skill.xf-yun.com.cn\`"
echo "- Public URL: \`${{ inputs.public_url }}\`"
echo "- Web base path: \`${{ inputs.web_base_path || '/' }}\`"
echo "- Base ref: \`${{ steps.batch.outputs.base_ref }}\`"
echo "- Floating tag: \`${{ steps.batch.outputs.deploy_tag }}\`"
echo "- Immutable tag: \`${{ steps.batch.outputs.immutable_tag }}\`"

View file

@ -13,6 +13,7 @@ on:
- 'web/docker-entrypoint.d/**'
- '.github/workflows/pr-cli.yml'
- '.github/workflows/pr-e2e.yml'
- '.github/workflows/pr-batch-test-deploy.yml'
- '.github/workflows/pr-helm-chart.yml'
- '.github/workflows/pr-tests.yml'
- '.github/workflows/publish-chart.yml'

View file

@ -16,6 +16,8 @@ Options:
--merged-sha <sha> Synthetic merge commit SHA
--pr-csv <list> Comma-separated PR numbers
--run-url <url> GitHub Actions run URL
--public-url <url> Public URL configured on the remote runtime
--web-base-path <path> Optional Web UI base path, for example /skillhub/
EOF
}
@ -28,6 +30,8 @@ immutable_tag=""
merged_sha=""
pr_csv=""
run_url=""
public_url=""
web_base_path=""
while [[ $# -gt 0 ]]; do
case "$1" in
@ -76,6 +80,16 @@ while [[ $# -gt 0 ]]; do
run_url="$2"
shift 2
;;
--public-url)
[[ $# -ge 2 ]] || { echo "Missing value for --public-url" >&2; exit 1; }
public_url="$2"
shift 2
;;
--web-base-path)
[[ $# -ge 2 ]] || { echo "Missing value for --web-base-path" >&2; exit 1; }
web_base_path="$2"
shift 2
;;
--help|-h)
usage
exit 0
@ -105,24 +119,15 @@ ssh_opts=(
-p "${ssh_port}"
)
ssh "${ssh_opts[@]}" "${ssh_user}@${ssh_host}" bash -s -- \
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
remote_script="${script_dir}/skillhub-test-deploy-remote.sh"
[[ -f "${remote_script}" ]] || { echo "Missing remote deploy script: ${remote_script}" >&2; exit 1; }
ssh "${ssh_opts[@]}" "${ssh_user}@${ssh_host}" sudo bash -s -- \
"${deploy_tag}" \
"${immutable_tag}" \
"${merged_sha}" \
"${pr_csv}" \
"${run_url}" <<'EOF'
set -euo pipefail
deploy_tag="$1"
immutable_tag="$2"
merged_sha="$3"
pr_csv="$4"
run_url="${5:-}"
sudo /usr/local/bin/skillhub-test-deploy \
--deploy-tag "${deploy_tag}" \
--immutable-tag "${immutable_tag}" \
--merged-sha "${merged_sha}" \
--pr-csv "${pr_csv}" \
--run-url "${run_url}"
EOF
"${run_url}" \
"${public_url}" \
"${web_base_path}" <"${remote_script}"

View file

@ -12,6 +12,8 @@ Options:
--merged-sha <sha> Synthetic merge commit SHA
--pr-csv <list> Comma-separated PR numbers
--run-url <url> GitHub Actions run URL
--public-url <url> Public URL configured on the remote runtime
--web-base-path <path> Optional Web UI base path, for example /skillhub/
EOF
}
@ -21,6 +23,20 @@ immutable_tag=""
merged_sha=""
pr_csv=""
run_url=""
public_url=""
web_base_path=""
if [[ $# -ge 7 && "${1:-}" != --* ]]; then
set -- \
--deploy-tag "$1" \
--immutable-tag "$2" \
--merged-sha "$3" \
--pr-csv "$4" \
--run-url "$5" \
--public-url "$6" \
--web-base-path "$7" \
"${@:8}"
fi
while [[ $# -gt 0 ]]; do
case "$1" in
@ -49,6 +65,16 @@ while [[ $# -gt 0 ]]; do
run_url="$2"
shift 2
;;
--public-url)
[[ $# -ge 2 ]] || { echo "Missing value for --public-url" >&2; exit 1; }
public_url="$2"
shift 2
;;
--web-base-path)
[[ $# -ge 2 ]] || { echo "Missing value for --web-base-path" >&2; exit 1; }
web_base_path="$2"
shift 2
;;
--help|-h)
usage
exit 0
@ -89,6 +115,11 @@ if [[ -n "${run_url}" && ! "${run_url}" =~ ^https://github\.com/.+/actions/runs/
exit 1
fi
if [[ -n "${public_url}" && ! "${public_url}" =~ ^https?://[^[:space:]/?#]+(:[0-9]+)?(/[^[:space:]?#]*)?$ ]]; then
echo "Invalid public URL: ${public_url}" >&2
exit 1
fi
set_env_value() {
key="$1"
value="$2"
@ -116,6 +147,44 @@ get_env_value() {
fi
}
normalize_base_path() {
local value="$1"
if [[ -z "${value}" || "${value}" == "/" ]]; then
printf '/'
return 0
fi
case "${value}" in
/*/) ;;
/*) value="${value}/" ;;
*) value="/${value}/" ;;
esac
case "${value}" in
*//*|*[!A-Za-z0-9._~/-]*)
echo "Invalid web base path: ${value}" >&2
exit 1
;;
*/./*|*/../*)
echo "Web base path must not contain '.' or '..' path segments: ${value}" >&2
exit 1
;;
esac
local first_segment
first_segment="${value#/}"
first_segment="${first_segment%%/*}"
case "${first_segment}" in
api|oauth2|login|assets|registry|nginx-health|.well-known|runtime-config.js)
echo "Web base path must not start with reserved SkillHub path segment: ${first_segment}" >&2
exit 1
;;
esac
printf '%s' "${value}"
}
wait_for_postgres_ready() {
postgres_user="$1"
postgres_db="$2"
@ -134,6 +203,23 @@ wait_for_postgres_ready() {
exit 1
}
wait_for_web_ready() {
local web_port="$1"
local health_path="$2"
for attempt in $(seq 1 60); do
if curl -fsS "http://127.0.0.1:${web_port}${health_path}" >/dev/null 2>&1; then
return 0
fi
sleep 2
done
echo "Web did not become ready in time: http://127.0.0.1:${web_port}${health_path}" >&2
docker compose --env-file .env.release -f compose.release.yml logs web >&2 || true
exit 1
}
ensure_postgres_password_matches_env() {
postgres_user="$(get_env_value "POSTGRES_USER" "skillhub")"
postgres_db="$(get_env_value "POSTGRES_DB" "skillhub")"
@ -170,6 +256,21 @@ cp .env.release ".env.release.bak.$(date +%Y%m%d%H%M%S)"
set_env_value "SKILLHUB_VERSION" "${deploy_tag}"
if [[ -n "${public_url}" ]]; then
set_env_value "SKILLHUB_PUBLIC_BASE_URL" "${public_url%/}"
fi
normalized_web_base_path=""
if [[ -n "${web_base_path}" ]]; then
normalized_web_base_path="$(normalize_base_path "${web_base_path}")"
set_env_value "SKILLHUB_WEB_BASE_PATH" "${normalized_web_base_path}"
if [[ "${normalized_web_base_path}" == "/" ]]; then
set_env_value "SKILLHUB_WEB_API_BASE_URL" ""
else
set_env_value "SKILLHUB_WEB_API_BASE_URL" "${normalized_web_base_path%/}"
fi
fi
cat > manual-test-deployment.txt <<METADATA
deployed_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)
deploy_tag=${deploy_tag}
@ -177,6 +278,8 @@ immutable_tag=${immutable_tag}
merged_sha=${merged_sha}
pr_numbers=${pr_csv}
run_url=${run_url}
public_url=${public_url}
web_base_path=${normalized_web_base_path:-}
METADATA
docker compose --env-file .env.release -f compose.release.yml pull
@ -191,4 +294,8 @@ if [[ -z "${web_port}" ]]; then
fi
curl -fsS http://127.0.0.1:8080/actuator/health >/dev/null
curl -fsS "http://127.0.0.1:${web_port}/nginx-health" >/dev/null
web_health_path="/nginx-health"
if [[ -n "${normalized_web_base_path}" && "${normalized_web_base_path}" != "/" ]]; then
web_health_path="${normalized_web_base_path%/}/nginx-health"
fi
wait_for_web_ready "${web_port}" "${web_health_path}"

View file

@ -55,6 +55,8 @@ grep -Fq '.github/workflows/pr-cli.yml' "$PR_SCRIPTS_WORKFLOW" \
|| fail "pr-scripts must run when PR CLI workflow changes"
grep -Fq '.github/workflows/pr-e2e.yml' "$PR_SCRIPTS_WORKFLOW" \
|| fail "pr-scripts must run when PR E2E workflow changes"
grep -Fq '.github/workflows/pr-batch-test-deploy.yml' "$PR_SCRIPTS_WORKFLOW" \
|| fail "pr-scripts must run when PR batch deploy workflow changes"
grep -Fq '.github/workflows/pr-helm-chart.yml' "$PR_SCRIPTS_WORKFLOW" \
|| fail "pr-scripts must run when PR Helm Chart workflow changes"
grep -Fq '.github/workflows/pr-tests.yml' "$PR_SCRIPTS_WORKFLOW" \