Skip to content

Commit 308fd8a

Browse files
fix(release): assert required release assets by presence in auto-promote (#460)
Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
1 parent 224670e commit 308fd8a

1 file changed

Lines changed: 38 additions & 7 deletions

File tree

.github/workflows/auto-promote.yaml

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,13 @@ jobs:
329329
330330
# Verify the published release matches expectations: not a draft, not a
331331
# prerelease (GoReleaser's prerelease:auto must classify a non-rc tag as a
332-
# final release), exactly 5 assets (4 archives + checksums.txt), and that
333-
# vX.Y.Z is the repo's latest release.
332+
# final release), that vX.Y.Z is the repo's latest release, and that the
333+
# required signing and checksum assets are attached. The presence checks
334+
# assert assets by name (checksums.txt plus its cosign .bundle and GPG
335+
# .asc signatures) and require at least four archive tarballs, rather than
336+
# a brittle exact asset count. GoReleaser also attaches per-archive SBOMs,
337+
# so the total asset count grows over time; asserting the load-bearing
338+
# assets by name keeps this gate stable as the artifact set expands.
334339
- name: Verify published release
335340
if: steps.idem.outputs.skip != 'true'
336341
env:
@@ -344,29 +349,55 @@ jobs:
344349
--json isDraft,isPrerelease,assets)
345350
IS_DRAFT=$(printf '%s' "$DATA" | jq -r '.isDraft')
346351
IS_PRERELEASE=$(printf '%s' "$DATA" | jq -r '.isPrerelease')
347-
ASSET_COUNT=$(printf '%s' "$DATA" | jq -r '.assets | length')
352+
ARCHIVE_COUNT=$(printf '%s' "$DATA" | jq -r \
353+
'[.assets[] | select(.name | endswith(".tar.gz"))] | length')
348354
349355
LATEST=$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" \
350356
--jq '.tag_name')
351357
358+
# Named assets that a signed final release must carry: the checksum
359+
# manifest plus the cosign (.bundle) and GPG (.asc) signatures over it.
360+
REQUIRED_ASSETS="checksums.txt checksums.txt.bundle checksums.txt.asc"
361+
MIN_ARCHIVES=4
362+
363+
has_asset() {
364+
printf '%s' "$DATA" | jq -e --arg n "$1" \
365+
'.assets | any(.name == $n)' >/dev/null
366+
}
367+
368+
fail=0
369+
352370
{
353371
echo "## Auto-promote: $BASE_VERSION"
354372
echo ""
355373
echo "| Check | Value | Expected |"
356374
echo "|---|---|---|"
357375
echo "| draft | $IS_DRAFT | false |"
358376
echo "| prerelease | $IS_PRERELEASE | false |"
359-
echo "| assets | $ASSET_COUNT | 5 |"
377+
} >> "$GITHUB_STEP_SUMMARY"
378+
379+
for name in $REQUIRED_ASSETS; do
380+
if has_asset "$name"; then
381+
present="yes"
382+
else
383+
present="no"
384+
echo "::error::$BASE_VERSION is missing required asset $name."
385+
fail=1
386+
fi
387+
echo "| asset: $name | $present | present |" >> "$GITHUB_STEP_SUMMARY"
388+
done
389+
390+
{
391+
echo "| archive tarballs (*.tar.gz) | $ARCHIVE_COUNT | >= $MIN_ARCHIVES |"
360392
echo "| latest release | $LATEST | $BASE_VERSION |"
361393
} >> "$GITHUB_STEP_SUMMARY"
362394
363-
fail=0
364395
[ "$IS_DRAFT" = "false" ] || { echo "::error::$BASE_VERSION is a draft."; fail=1; }
365396
[ "$IS_PRERELEASE" = "false" ] || { echo "::error::$BASE_VERSION is marked prerelease; GoReleaser misclassified a non-rc tag."; fail=1; }
366-
[ "$ASSET_COUNT" = "5" ] || { echo "::error::$BASE_VERSION has $ASSET_COUNT assets, expected 5."; fail=1; }
397+
[ "$ARCHIVE_COUNT" -ge "$MIN_ARCHIVES" ] || { echo "::error::$BASE_VERSION has $ARCHIVE_COUNT archive tarballs, expected at least $MIN_ARCHIVES."; fail=1; }
367398
[ "$LATEST" = "$BASE_VERSION" ] || { echo "::error::latest release is $LATEST, expected $BASE_VERSION."; fail=1; }
368399
369400
if [ "$fail" -ne 0 ]; then
370401
exit 1
371402
fi
372-
echo "::notice::$BASE_VERSION published as latest, non-prerelease, with 5 assets."
403+
echo "::notice::$BASE_VERSION published as latest, non-prerelease, with the required checksum and signature assets and $ARCHIVE_COUNT archive tarballs."

0 commit comments

Comments
 (0)