diff --git a/.github/workflows/release-latest-guard.yml b/.github/workflows/release-latest-guard.yml new file mode 100644 index 000000000..8acf55daf --- /dev/null +++ b/.github/workflows/release-latest-guard.yml @@ -0,0 +1,57 @@ +name: Release latest guard + +# Guard against accidental non-stable GitHub releases taking over +# /releases/latest and breaking electron-updater's stable channel. +on: + release: + types: [published, edited, released] + schedule: + - cron: "17 * * * *" + workflow_dispatch: + +jobs: + latest-release: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Verify latest stable release + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + shell: bash + run: | + set -euo pipefail + + release_json="$(gh release view --repo "$REPO" --json tagName,isPrerelease,isDraft,assets)" + tag="$(jq -r '.tagName' <<<"$release_json")" + prerelease="$(jq -r '.isPrerelease' <<<"$release_json")" + draft="$(jq -r '.isDraft' <<<"$release_json")" + + echo "Latest release: $tag" + + if [[ "$draft" == "true" || "$prerelease" == "true" ]]; then + echo "::error::GitHub latest resolved to draft/prerelease '$tag'; stable latest must be a published non-prerelease." + exit 1 + fi + + if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::GitHub latest resolved to '$tag'; expected a stable semver tag like v0.10.2." + exit 1 + fi + + mapfile -t assets < <(jq -r '.assets[].name' <<<"$release_json") + printf 'Assets:\n%s\n' "${assets[@]}" + + required_assets=( + latest.yml + latest-mac.yml + latest-linux.yml + ) + + for required in "${required_assets[@]}"; do + if ! printf '%s\n' "${assets[@]}" | grep -Fxq "$required"; then + echo "::error::Latest stable release '$tag' is missing updater feed asset '$required'." + exit 1 + fi + done