fix(release): keep publication off GitHub-only actions (#1)

upload-artifact@v4 speaks the v2 artifacts API, which this Gitea answers
only at its v3-era shape, so the sixth release attempt cleared every gate
and then aborted at "Preserve verified candidate artifacts" with the GHES
compatibility error. Move the step to v3.2.1, the commit the upstream v3
tag resolves to, which keeps name, path, if-no-files-found and
retention-days unchanged. The step also becomes continue-on-error: it is a
pre-publish debugging backstop, and publish-release.sh attaches the same
directory as Gitea release assets, so losing it must never cost a release.

Replace cosign-installer with the direct fetch the scanner already uses.
The action issues no API call on this path, but it is a composite action
resting on envsubst and a resolved runner.arch, neither of which this
runner has exercised. Asked for the version it bootstraps, it downloads
exactly cosign-linux-amd64 from the v3.0.6 release, compares it against
c956e5df..., and exits; that digest matches the release checksums file, so
fetching the asset directly verifies identically with nothing unproven
left before the one-way publication gate. The binary joins the PATH that
publish-release.sh already resolves dotnet through.
This commit is contained in:
KyuubiYoru
2026-08-22 22:10:00 +02:00
parent 747e3bb9c3
commit a6a98f211d
2 changed files with 55 additions and 4 deletions
+30 -4
View File
@@ -262,7 +262,13 @@ jobs:
_ "$RENDEZVOUS_RELEASE_DIR" "$RENDEZVOUS_VERSION" "$GITHUB_SHA" "$source_date_epoch" _ "$RENDEZVOUS_RELEASE_DIR" "$RENDEZVOUS_VERSION" "$GITHUB_SHA" "$source_date_epoch"
- name: Preserve verified candidate artifacts - name: Preserve verified candidate artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 # upload-artifact@v4 speaks the v2 artifacts API, which this Gitea only
# answers at its v3-era shape, so v4 aborts before uploading anything.
# Keeping the candidate is a pre-publish debugging backstop, not a
# release gate: publish-release.sh attaches the same files as Gitea
# release assets, so a failure here must never block a release.
continue-on-error: true
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3.2.1
with: with:
name: rendezvous-${{ env.RENDEZVOUS_VERSION }} name: rendezvous-${{ env.RENDEZVOUS_VERSION }}
path: ${{ env.RENDEZVOUS_RELEASE_DIR }} path: ${{ env.RENDEZVOUS_RELEASE_DIR }}
@@ -270,9 +276,29 @@ jobs:
retention-days: 30 retention-days: 30
- name: Install pinned signing client - name: Install pinned signing client
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 shell: bash
with: run: |
cosign-release: v3.0.6 set -euo pipefail
# cosign-installer issues no API call on the pinned path, but it is a
# composite action resting on `envsubst` and a resolved runner.arch,
# neither of which this runner has ever exercised. Asked for the same
# version it bootstraps, the action downloads exactly this asset and
# checks it against exactly this digest before declaring itself done,
# so fetching it directly verifies identically with nothing unproven
# left in the path. The digest is pinned inline for the reason the
# scanner's is: a checksums file fetched at run time only proves the
# asset matches whatever the release currently serves.
cosign_bin_dir="$RENDEZVOUS_WORK_DIR/bin"
mkdir -p "$cosign_bin_dir"
curl --fail --location --silent --show-error --output "$cosign_bin_dir/cosign" \
https://github.com/sigstore/cosign/releases/download/v3.0.6/cosign-linux-amd64
echo "c956e5dfcac53d52bcf058360d579472f0c1d2d9b69f55209e256fe7783f4c74 $cosign_bin_dir/cosign" \
| sha256sum --check --strict -
chmod +x "$cosign_bin_dir/cosign"
# publish-release.sh resolves cosign through `command -v`, so the
# directory joins the PATH the same way the action would have added it.
echo "$cosign_bin_dir" >>"$GITHUB_PATH"
"$cosign_bin_dir/cosign" version
- name: Publish once, sign, attest, and create release - name: Publish once, sign, attest, and create release
shell: bash shell: bash
@@ -97,6 +97,31 @@ public sealed class ReleaseCompatibilityTests
StringComparison.Ordinal); StringComparison.Ordinal);
Assert.Contains("sha256sum --check --strict", workflow, StringComparison.Ordinal); Assert.Contains("sha256sum --check --strict", workflow, StringComparison.Ordinal);
Assert.Contains("TRIVY_CACHE_DIR=$RENDEZVOUS_WORK_DIR/trivy-cache", workflow, StringComparison.Ordinal); Assert.Contains("TRIVY_CACHE_DIR=$RENDEZVOUS_WORK_DIR/trivy-cache", workflow, StringComparison.Ordinal);
// Gitea answers the v3-era artifacts API only, so upload-artifact stays on
// v3 and never gates the release it is only meant to help debug.
Assert.DoesNotContain(
"actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02",
workflow,
StringComparison.Ordinal);
Assert.Contains(
"actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3.2.1",
workflow,
StringComparison.Ordinal);
Assert.Contains("continue-on-error: true", workflow, StringComparison.Ordinal);
// The signing client is fetched the way the scanner is: a pinned asset
// checked against a pinned digest, with no action resolved off github.com.
Assert.DoesNotContain("sigstore/cosign-installer", workflow, StringComparison.Ordinal);
Assert.Contains(
"https://github.com/sigstore/cosign/releases/download/v3.0.6/cosign-linux-amd64",
workflow,
StringComparison.Ordinal);
Assert.Contains(
"c956e5dfcac53d52bcf058360d579472f0c1d2d9b69f55209e256fe7783f4c74",
workflow,
StringComparison.Ordinal);
Assert.Contains("echo \"$cosign_bin_dir\" >>\"$GITHUB_PATH\"", workflow, StringComparison.Ordinal);
Assert.Contains("--exit-code 1", workflow, StringComparison.Ordinal); Assert.Contains("--exit-code 1", workflow, StringComparison.Ordinal);
Assert.Contains("--severity HIGH,CRITICAL", workflow, StringComparison.Ordinal); Assert.Contains("--severity HIGH,CRITICAL", workflow, StringComparison.Ordinal);
Assert.DoesNotContain("--ignore-unfixed", workflow, StringComparison.Ordinal); Assert.DoesNotContain("--ignore-unfixed", workflow, StringComparison.Ordinal);