fix(deploy): configure HK sub-path validation

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-08-06 15:54:45 +08:00
parent 7ce5b73b71
commit 0f0e057779
2 changed files with 108 additions and 9 deletions

View file

@ -20,8 +20,9 @@ When you trigger the workflow manually, it:
6. builds `server`, `web`, and `scanner` images for `linux/amd64`
7. pushes both a floating tag and an immutable tag to GHCR
8. SSHes into the HK test machine as a dedicated deploy user
9. calls a root-owned deployment wrapper through `sudo`
10. updates `/opt/skillhub-runtime/.env.release` and runs `docker compose pull && docker compose up -d`
9. updates the selected non-secret runtime fields in `/opt/skillhub-runtime/.env.release`
10. calls a root-owned deployment wrapper through `sudo`
11. runs `docker compose pull && docker compose up -d` through the remote wrapper
The floating tag is the shared environment channel. By default it is
`manual-test-hk`. Each run also pushes an immutable tag for traceability:
@ -59,9 +60,37 @@ Open the workflow in GitHub Actions and fill in:
- `pr_numbers`: a comma-separated or newline-separated list such as `123, 124, 130`
- `base_ref`: usually `main`
- `deploy_channel`: keep the default `manual-test-hk` for the shared test machine
- `public_url`: the public URL to write into `SKILLHUB_PUBLIC_BASE_URL`
- `web_base_path`: optional sub-path to write into `SKILLHUB_WEB_BASE_PATH`; when set,
the workflow also writes `SKILLHUB_WEB_API_BASE_URL` to the same path without the
trailing slash
The merge order matters. If PR `124` depends on `123`, list `123` first.
For sub-path verification, use a unique deploy channel so Compose recreates the
containers even if the shared floating tag already exists:
```text
deploy_channel=manual-test-hk-<short-sha>
public_url=https://skill.xf-yun.com.cn/skillhub
web_base_path=/skillhub/
```
The workflow must verify that `/skillhub/runtime-config.js` returns the generated
JavaScript runtime config, not the SPA fallback HTML.
## OSS quickstart synchronization
The one-line quickstart downloads `runtime.sh`, and that script downloads:
- `compose.release.yml`
- `.env.release.example`
When runtime flags, release Compose wiring, or release env defaults change, publish
all three files to the OSS origin together. If `--aliyun` or another mirror registry
is used, the corresponding `skillhub-server`, `skillhub-web`, and
`skillhub-scanner` image tags must also be mirrored.
## Runtime metadata on the server
After deployment, the workflow writes a small metadata file here:

View file

@ -136,6 +136,82 @@ pr_csv="$4"
run_url="${5:-}"
public_url="${6:-}"
web_base_path="${7:-}"
runtime_dir="/opt/skillhub-runtime"
env_file="${runtime_dir}/.env.release"
set_env_value() {
local key="$1"
local value="$2"
local tmp
tmp="$(mktemp "${env_file}.tmp.XXXXXX")"
if grep -q "^${key}=" "${env_file}"; then
sed "s|^${key}=.*|${key}=${value}|" "${env_file}" >"${tmp}"
else
cp "${env_file}" "${tmp}"
printf '%s=%s\n' "${key}" "${value}" >>"${tmp}"
fi
mv "${tmp}" "${env_file}"
}
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}"
}
[[ -f "${env_file}" ]] || { echo "Missing HK runtime env file: ${env_file}" >&2; exit 1; }
if [[ -n "${public_url}" ]]; then
if [[ ! "${public_url}" =~ ^https?://[^[:space:]/?#]+(:[0-9]+)?(/[^[:space:]?#]*)?$ ]]; then
echo "Invalid public URL: ${public_url}" >&2
exit 1
fi
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
deploy_status=0
sudo /usr/local/bin/skillhub-test-deploy \
@ -153,13 +229,7 @@ if [[ ! -r /opt/skillhub-runtime/manual-test-deployment.txt ]] || \
fi
web_health_paths=("/nginx-health")
if [[ -n "${web_base_path}" && "${web_base_path}" != "/" ]]; then
normalized_web_base_path="${web_base_path}"
case "${normalized_web_base_path}" in
/*/) ;;
/*) normalized_web_base_path="${normalized_web_base_path}/" ;;
*) normalized_web_base_path="/${normalized_web_base_path}/" ;;
esac
if [[ -n "${normalized_web_base_path}" && "${normalized_web_base_path}" != "/" ]]; then
web_health_paths+=("${normalized_web_base_path%/}/nginx-health")
fi