[codex] Guard latest desktop release (#2463)

* ci: guard latest desktop release

* fix(ci): self-heal a hijacked releases/latest pointer (#2462)

The guard previously only detected a hijacked latest pointer and failed the
run, still requiring a maintainer with delete rights to remove the junk
release by hand.

Add a remediation step that, on scheduled/manual runs, deletes a release
carrying the unambiguous hijack signature -- published, non-prerelease, a
non-semver tag, and zero electron-updater feed assets (latest.yml /
latest-mac.yml / latest-linux.yml) -- along with its tag, so GitHub
re-points latest to the newest real stable release. A real stable release
always has a semver tag and the feed assets, so this can never match one; an
in-progress real release keeps its semver tag, so it is excluded too, and the
step never runs on `release` events to avoid racing an asset upload.

This lets merging the PR resolve #2462 via the Actions token with no manual
admin action, while the verify step stays as the tripwire for anything
outside the auto-remediable signature. Bumps the job permission from
contents:read to contents:write for the delete.

* Revert "fix(ci): self-heal a hijacked releases/latest pointer (#2462)"

This reverts commit 185bc563a9.
This commit is contained in:
Deepak Modi 2026-07-07 21:34:07 +05:30 committed by GitHub
parent 3423dde505
commit 6d53e1155c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 57 additions and 0 deletions

View File

@ -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