fix: harden proxied client installation
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
CI / Client installer (macos-latest) (push) Canceled after 0s
CI / Client installer (ubuntu-latest) (push) Canceled after 0s
CI / Client installer (windows-latest) (push) Canceled after 0s
CI / test (22) (push) Canceled after 0s
CI / test (24) (push) Canceled after 0s
CI / release-smoke (push) Canceled after 0s
This commit is contained in:
+70
-11
@@ -6,6 +6,7 @@ domain="approval.justconn.top"
|
||||
public_base_url="https://${domain}"
|
||||
gateway_url="${public_base_url}/mcp"
|
||||
download_base_url="${public_base_url}/downloads/dingmcp"
|
||||
gitea_repo="gitea-admin/dingMCP"
|
||||
release_dir="${project_root}/release"
|
||||
web_base="/var/www/${domain}"
|
||||
web_root="${web_base}/downloads/dingmcp"
|
||||
@@ -17,13 +18,29 @@ npm_cache="${project_root}/.npm-cache"
|
||||
release_private_key="${project_root}/.secrets/release-signing-private.pem"
|
||||
release_public_key="${project_root}/distribution/release-signing-public.pem"
|
||||
|
||||
for command_name in node npm curl systemctl sudo nginx certbot stat sha256sum tar find sort tail cut date; do
|
||||
for command_name in node npm curl systemctl sudo nginx certbot stat sha256sum tar find sort tail cut date git tea; do
|
||||
command -v "${command_name}" >/dev/null 2>&1 || {
|
||||
echo "缺少部署命令:${command_name}" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
cd "${project_root}"
|
||||
release_version="$(node -p "require('./package.json').version")"
|
||||
release_tag="v${release_version}"
|
||||
download_mirror_base_url="https://git.justconn.top/${gitea_repo}/releases/download/${release_tag}"
|
||||
if [[ "$(git branch --show-current)" != "main" ]] || ! git diff --quiet || ! git diff --cached --quiet; then
|
||||
echo "正式部署只能从无未提交改动的 main 分支执行。" >&2
|
||||
exit 1
|
||||
fi
|
||||
release_commit="$(git rev-parse HEAD)"
|
||||
release_created_at="$(git show -s --format=%cI "${release_commit}")"
|
||||
remote_main="$(git ls-remote origin refs/heads/main | cut -f1)"
|
||||
if [[ -z "${remote_main}" || "${remote_main}" != "${release_commit}" ]]; then
|
||||
echo "当前 main 提交尚未同步到 Gitea origin/main,拒绝创建发布标签。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${project_root}/.runtime/dingtalk-mcp.env" ]]; then
|
||||
echo "缺少 .runtime/dingtalk-mcp.env;首次部署前需先配置网关企业凭证。" >&2
|
||||
exit 1
|
||||
@@ -38,15 +55,16 @@ if [[ "$(stat -c '%a' "${release_private_key}")" != "600" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[1/7] 测试并构建"
|
||||
cd "${project_root}"
|
||||
echo "[1/8] 测试并构建"
|
||||
npm --cache "${npm_cache}" test
|
||||
npm run runtime:verify
|
||||
|
||||
echo "[2/7] 生成包含钉钉 OA 与薪福通的发行包"
|
||||
echo "[2/8] 生成包含钉钉 OA 与薪福通的发行包"
|
||||
npm --cache "${npm_cache}" run release:build -- \
|
||||
--gateway-url "${gateway_url}" \
|
||||
--download-base-url "${download_base_url}" \
|
||||
--download-mirror-base-url "${download_mirror_base_url}" \
|
||||
--created-at "${release_created_at}" \
|
||||
--out release
|
||||
npm run test-bundle:build -- \
|
||||
--release-dir release \
|
||||
@@ -56,11 +74,49 @@ npm run test-bundle:build -- \
|
||||
(cd "${release_dir}" && sha256sum -c SHA256SUMS)
|
||||
npm run release:verify -- --release-dir release
|
||||
|
||||
echo "[3/7] 安装并重启用户级网关服务"
|
||||
echo "[3/8] 发布或复用 Gitea 国内备用下载源"
|
||||
gitea_releases_json="$(mktemp)"
|
||||
trap 'rm -f "${gitea_releases_json}"' EXIT
|
||||
tea releases list --remote origin --limit 100 --output json >"${gitea_releases_json}"
|
||||
if ! node -e 'const fs=require("fs");const tag=process.argv[1];const rows=JSON.parse(fs.readFileSync(0,"utf8"));process.exit(rows.some((row)=>row.tag_name===tag||row.tag===tag||row.Tag===tag)?0:1)' \
|
||||
"${release_tag}" <"${gitea_releases_json}"; then
|
||||
release_flags=()
|
||||
[[ "${release_version}" == *-* ]] && release_flags+=(--prerelease)
|
||||
tea releases create --remote origin --tag "${release_tag}" --target "${release_commit}" \
|
||||
--title "${release_tag}" --note "Signed DingTalk approval client ${release_version}" "${release_flags[@]}"
|
||||
fi
|
||||
mapfile -t mirror_assets < <(find "${release_dir}" -mindepth 1 -maxdepth 1 -type f -print | sort)
|
||||
missing_mirror_assets=()
|
||||
mirror_check_file="$(mktemp)"
|
||||
for asset in "${mirror_assets[@]}"; do
|
||||
asset_name="$(basename "${asset}")"
|
||||
if curl --fail --silent --location "${download_mirror_base_url}/${asset_name}" -o "${mirror_check_file}" 2>/dev/null; then
|
||||
if [[ "$(sha256sum "${mirror_check_file}" | cut -d' ' -f1)" != "$(sha256sum "${asset}" | cut -d' ' -f1)" ]]; then
|
||||
echo "Gitea 已存在同版本但内容不同的发布物:${asset_name};请提升版本号后重新发布。" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
missing_mirror_assets+=("${asset}")
|
||||
fi
|
||||
done
|
||||
if ((${#missing_mirror_assets[@]} > 0)); then
|
||||
tea releases assets create --remote origin "${release_tag}" "${missing_mirror_assets[@]}"
|
||||
fi
|
||||
for asset in "${mirror_assets[@]}"; do
|
||||
asset_name="$(basename "${asset}")"
|
||||
curl --fail --silent --show-error --location "${download_mirror_base_url}/${asset_name}" -o "${mirror_check_file}"
|
||||
[[ "$(sha256sum "${mirror_check_file}" | cut -d' ' -f1)" == "$(sha256sum "${asset}" | cut -d' ' -f1)" ]] || {
|
||||
echo "Gitea 备用发布物校验失败:${asset_name}" >&2
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
rm -f "${mirror_check_file}" "${gitea_releases_json}"
|
||||
trap - EXIT
|
||||
|
||||
echo "[4/8] 安装并重启用户级网关服务"
|
||||
node dist/src/admin.js service start --project-root "${project_root}"
|
||||
|
||||
echo "[4/7] 原子发布安装文件"
|
||||
release_version="$(node -p "require('./package.json').version")"
|
||||
echo "[5/8] 原子发布安装文件"
|
||||
release_digest="$(sha256sum "${release_dir}/manifest.json" | cut -c1-12)"
|
||||
release_name="${release_version}-${release_digest}"
|
||||
release_target="${web_releases}/${release_name}"
|
||||
@@ -87,21 +143,21 @@ for obsolete in "${obsolete_releases[@]}"; do
|
||||
done
|
||||
|
||||
if ! sudo test -f "${certificate}"; then
|
||||
echo "[5/7] 首次签发 HTTPS 证书"
|
||||
echo "[6/8] 首次签发 HTTPS 证书"
|
||||
sudo install -m 0644 "${project_root}/deploy/${domain}.bootstrap.nginx.conf" "${nginx_site}"
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
sudo certbot certonly --webroot -w "${acme_root}" -d "${domain}"
|
||||
else
|
||||
echo "[5/7] 复用现有 HTTPS 证书"
|
||||
echo "[6/8] 复用现有 HTTPS 证书"
|
||||
fi
|
||||
|
||||
echo "[6/7] 安装正式 Nginx 配置"
|
||||
echo "[7/8] 安装正式 Nginx 配置"
|
||||
sudo install -m 0644 "${project_root}/deploy/${domain}.nginx.conf" "${nginx_site}"
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
|
||||
echo "[7/7] 验证公网服务"
|
||||
echo "[8/8] 验证公网服务与备用发布源"
|
||||
curl --fail --silent --show-error --retry 10 --retry-delay 1 --retry-all-errors \
|
||||
"${public_base_url}/healthz" >/dev/null
|
||||
curl --fail --silent --show-error \
|
||||
@@ -111,8 +167,11 @@ curl --fail --silent --show-error "${download_base_url}/manifest.json" >/dev/nul
|
||||
curl --fail --silent --show-error "${download_base_url}/manifest.sig" >/dev/null
|
||||
curl --fail --silent --show-error "${download_base_url}/dingtalk-approval-installer.mjs" >/dev/null
|
||||
curl --fail --silent --show-error "${download_base_url}/release-signing-public.pem" >/dev/null
|
||||
curl --fail --silent --show-error --location "${download_mirror_base_url}/manifest.json" >/dev/null
|
||||
curl --fail --silent --show-error --location "${download_mirror_base_url}/manifest.sig" >/dev/null
|
||||
|
||||
echo "部署完成。"
|
||||
echo "MCP:${gateway_url}"
|
||||
echo "用户安装链接:${download_base_url}/install.md"
|
||||
echo "备用安装链接:${download_mirror_base_url}/install.md"
|
||||
echo "黑盒测试提示词:${download_base_url}/agent-test-install.md"
|
||||
|
||||
Reference in New Issue
Block a user