fix(release): complete protected publish tooling

This commit is contained in:
Peter Steinberger
2026-07-15 10:37:45 +01:00
parent 3fccaec469
commit dfa246e6fd
6 changed files with 279 additions and 13 deletions

View File

@@ -554,6 +554,7 @@ jobs:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
persist-credentials: false
- name: Validate npm release request
@@ -569,18 +570,33 @@ jobs:
RELEASE_TAG: ${{ inputs.tag }}
RELEASE_NPM_DIST_TAG: ${{ inputs.npm_dist_tag }}
WORKFLOW_REF: ${{ github.ref }}
WORKFLOW_SHA: ${{ github.workflow_sha }}
run: |
set -euo pipefail
tideclaw_alpha_publish=false
extended_stable_publish=false
sha_pinned_release_publish=false
if [[ "${RELEASE_TAG}" == *"-alpha."* && "${RELEASE_NPM_DIST_TAG}" == "alpha" && "${WORKFLOW_REF}" =~ ^refs/heads/tideclaw/alpha/[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}Z$ ]]; then
tideclaw_alpha_publish=true
fi
if [[ "${RELEASE_NPM_DIST_TAG}" == "extended-stable" && "${WORKFLOW_REF}" == refs/heads/extended-stable/* ]]; then
extended_stable_publish=true
fi
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]] && [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/release/[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*$ ]] && [[ "${tideclaw_alpha_publish}" != "true" ]] && [[ "${extended_stable_publish}" != "true" ]]; then
echo "Real publish runs must be dispatched from main, release/YYYY.M.PATCH, the exact validated extended-stable branch, or a Tideclaw alpha branch for alpha prereleases. Use preflight_only=true for other branch validation."
if [[ "${WORKFLOW_REF}" =~ ^refs/tags/release-publish/([a-f0-9]{12})-[1-9][0-9]*$ ]]; then
workflow_sha_prefix="${BASH_REMATCH[1]}"
[[ "${WORKFLOW_SHA}" =~ ^[a-f0-9]{40}$ && "${WORKFLOW_SHA:0:12}" == "${workflow_sha_prefix}" ]] || {
echo "SHA-pinned release-publish tag does not match the OpenClaw npm workflow SHA." >&2
exit 1
}
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
git merge-base --is-ancestor "${WORKFLOW_SHA}" origin/main || {
echo "SHA-pinned OpenClaw npm workflow revision is not reachable from current main." >&2
exit 1
}
sha_pinned_release_publish=true
fi
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]] && [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/release/[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*$ ]] && [[ "${tideclaw_alpha_publish}" != "true" ]] && [[ "${extended_stable_publish}" != "true" ]] && [[ "${sha_pinned_release_publish}" != "true" ]]; then
echo "Real publish runs must be dispatched from main, release/YYYY.M.PATCH, a protected SHA-pinned release-publish tag, the exact validated extended-stable branch, or a Tideclaw alpha branch for alpha prereleases. Use preflight_only=true for other branch validation."
exit 1
fi

View File

@@ -1034,14 +1034,17 @@ jobs:
if [[ "$state" != "$last_state" ]]; then
echo "${workflow} still ${status} (updated ${updated_at}): ${url}"
print_pending_deployments "${workflow}" "${run_id}"
approval_status=0
approve_pending_deployments "${workflow}" "${run_id}" "${expected_sha}" ||
approval_status=$?
if (( approval_status > 1 )); then
return 1
fi
last_state="$state"
fi
# The deployment gate can appear after the run first reports
# waiting without changing updatedAt. Retry every poll so that
# propagation lag cannot strand an approved release.
approval_status=0
approve_pending_deployments "${workflow}" "${run_id}" "${expected_sha}" ||
approval_status=$?
if (( approval_status > 1 )); then
return 1
fi
sleep 30
done
@@ -1838,7 +1841,9 @@ jobs:
verify_args+=(--npm-telegram-run "${NPM_TELEGRAM_RUN_ID}")
fi
node --import tsx \
OPENCLAW_NPM_EXPECTED_WORKFLOW_REF="${GITHUB_REF}" \
OPENCLAW_NPM_EXPECTED_WORKFLOW_SHA="${PARENT_WORKFLOW_SHA}" \
node --import tsx \
"${GITHUB_WORKSPACE}/.release-harness/scripts/release-verify-beta.ts" \
"${verify_args[@]}"

View File

@@ -1085,13 +1085,22 @@ jobs:
exit 1
}
if [[ "$publish_route" == "npm-token-bootstrap" ]]; then
[[ "$WORKFLOW_REF" == "refs/heads/main" ]] || {
echo "npm token bootstrap requires the trusted main plugin release workflow." >&2
sha_pinned_release_publish=false
if [[ "$WORKFLOW_REF" =~ ^refs/tags/release-publish/([a-f0-9]{12})-[1-9][0-9]*$ ]]; then
workflow_sha_prefix="${BASH_REMATCH[1]}"
[[ "$WORKFLOW_SHA" =~ ^[a-f0-9]{40}$ && "${WORKFLOW_SHA:0:12}" == "$workflow_sha_prefix" ]] || {
echo "npm token bootstrap release-publish tag does not match the workflow SHA." >&2
exit 1
}
sha_pinned_release_publish=true
fi
[[ "$WORKFLOW_REF" == "refs/heads/main" || "$sha_pinned_release_publish" == "true" ]] || {
echo "npm token bootstrap requires trusted main tooling or a protected SHA-pinned release-publish tag." >&2
exit 1
}
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
git merge-base --is-ancestor "$WORKFLOW_SHA" origin/main || {
echo "npm token bootstrap workflow revision is not reachable from main." >&2
echo "npm token bootstrap workflow revision is not reachable from current main." >&2
exit 1
}
fi