[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:
parent
3423dde505
commit
6d53e1155c
|
|
@ -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
|
||||
Loading…
Reference in New Issue