mirror of
https://github.com/pgsty/silo.git
synced 2026-10-03 20:20:42 +00:00
6740e6978f
actions/checkout@v4 and actions/setup-go@v5 declare runs.using: node20, so every Go CI job printed the runner's Node 20 deprecation warning. The release, test-release and docker-release workflows carried six more node20 actions that never appeared in that warning only because those workflows run on a tag or a dispatch rather than on every push: upload-artifact v4, goreleaser-action v6, build-push v6 and the docker qemu/buildx/login v3 line. All of them move to the current majors, which declare node24. The SHA-pinned rest already qualified -- attest and sbom-action are node24, cosign-installer is composite. Checked against what those majors removed. build-push v7 dropped DOCKER_BUILD_NO_SUMMARY and DOCKER_BUILD_EXPORT_RETENTION_DAYS and setup-buildx v4 dropped its deprecated inputs, none of which are used here. checkout v7 refuses to check out fork PRs under pull_request_target and workflow_run, and no workflow here triggers on either. setup-go v6 exports GOTOOLCHAIN=local, the one change with teeth. go.mod declares `go 1.26.5` and carries no toolchain directive, every job resolves that same version through go-version-file, and nothing in the module graph asks for more, so there is nothing left for the go command to fetch: `go build ./...` passes under GOTOOLCHAIN=local. The tools installed from outside the module are in range too -- nfpm v2.47.0 requires 1.26.4 and govulncheck v1.6.0 requires 1.25.0 -- and golangci-lint arrives as a prebuilt binary from upstream's install script, not through the toolchain. The runner floor that comes with node24 (v2.327.1) is met by GitHub-hosted runners, and every job here is ubuntu-latest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
213 lines
7.9 KiB
YAML
213 lines
7.9 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "RELEASE.*"
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: "Release tag (e.g. RELEASE.2026-03-24T12-00-00Z)"
|
|
required: true
|
|
|
|
permissions:
|
|
contents: write
|
|
id-token: write
|
|
attestations: write
|
|
artifact-metadata: write
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v7
|
|
with:
|
|
fetch-depth: 0
|
|
# Build the code at the tag being released, not whatever branch the
|
|
# dispatch ran from. On a tag push this is the tag ref already; on
|
|
# workflow_dispatch it pins the checkout to the requested tag so the
|
|
# artifacts cannot be built from one ref and published under another.
|
|
ref: ${{ github.event.inputs.tag || github.ref }}
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@v7
|
|
with:
|
|
go-version-file: go.mod
|
|
cache: true
|
|
|
|
- name: Verify clean checkout
|
|
run: |
|
|
set -euo pipefail
|
|
# GitHub's OIDC certificate records GITHUB_SHA, not the ref passed to
|
|
# actions/checkout. A manual dispatch must therefore be launched from
|
|
# the release tag itself; otherwise the provenance identity would
|
|
# describe different source from the bytes being published.
|
|
CHECKED_OUT_REVISION="$(git rev-parse HEAD)"
|
|
if [ "${CHECKED_OUT_REVISION}" != "${GITHUB_SHA}" ]; then
|
|
echo "Checked out ${CHECKED_OUT_REVISION}, but workflow identity is ${GITHUB_SHA}. Dispatch from the release tag." >&2
|
|
exit 1
|
|
fi
|
|
if [ -n "$(git status --porcelain)" ]; then
|
|
echo "Refusing to release from a dirty working tree:" >&2
|
|
git status --porcelain >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Verify rebrand compatibility contracts
|
|
run: |
|
|
set -euo pipefail
|
|
go run ./buildscripts/rebrand-guard
|
|
buildscripts/verify-rebrand.sh
|
|
dockerscripts/docker-entrypoint_test.sh
|
|
|
|
- name: Compute release variables
|
|
env:
|
|
# Passed through the environment, never interpolated into the script
|
|
# body: a dispatch input reaches bash as data, so it cannot inject
|
|
# commands the way a `${{ ... }}` splice into the source would.
|
|
INPUT_TAG: ${{ github.event.inputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
TAG="${INPUT_TAG:-${GITHUB_REF_NAME}}"
|
|
# Whitelist the exact tag shape before the value is used anywhere. bash
|
|
# =~ anchors ^...$ to the whole string (not per line, as sed would), so
|
|
# a tag carrying a newline cannot pass and then smuggle extra lines into
|
|
# $GITHUB_ENV below.
|
|
if [[ ! "${TAG}" =~ ^RELEASE\.[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}-[0-9]{2}-[0-9]{2}Z$ ]]; then
|
|
echo "Invalid release tag format: ${TAG}" >&2
|
|
exit 1
|
|
fi
|
|
VERSION_HYPHEN="${TAG#RELEASE.}"
|
|
PKG_VERSION="$(echo "${VERSION_HYPHEN}" | sed -E 's/^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2})-([0-9]{2})-([0-9]{2})Z$/\1\2\3\4\5\6.0.0/')"
|
|
VERSION_COLON="$(echo "${VERSION_HYPHEN}" | sed -E 's/T([0-9]{2})-([0-9]{2})-([0-9]{2})Z$/T\1:\2:\3Z/')"
|
|
LDFLAGS="$(MINIO_RELEASE=RELEASE go run buildscripts/gen-ldflags.go "${VERSION_COLON}")"
|
|
|
|
{
|
|
echo "RELEASE_TAG=${TAG}"
|
|
echo "PKG_VERSION=${PKG_VERSION}"
|
|
echo "LDFLAGS=${LDFLAGS}"
|
|
} >> "${GITHUB_ENV}"
|
|
|
|
echo "Release tag: ${TAG}"
|
|
echo "Package version: ${PKG_VERSION}"
|
|
echo "LDFLAGS: ${LDFLAGS}"
|
|
|
|
# Both installer actions are pinned to immutable commits. The explicit
|
|
# tool versions keep the release format reproducible across workflow
|
|
# reruns while the installers verify the downloaded executables.
|
|
- name: Install Syft
|
|
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
|
|
with:
|
|
syft-version: v1.50.0
|
|
|
|
- name: Install Cosign
|
|
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
|
|
with:
|
|
cosign-release: v3.1.2
|
|
|
|
- name: Build Draft release with GoReleaser
|
|
uses: goreleaser/goreleaser-action@v7
|
|
with:
|
|
version: "~> v2"
|
|
args: release --clean --skip=validate --config .github/goreleaser.yml
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
LDFLAGS: ${{ env.LDFLAGS }}
|
|
PKG_VERSION: ${{ env.PKG_VERSION }}
|
|
|
|
- name: Verify binary provenance stamps
|
|
run: |
|
|
set -euo pipefail
|
|
buildscripts/verify-build-provenance.sh
|
|
|
|
- name: Install nFPM
|
|
run: |
|
|
set -euo pipefail
|
|
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.47.0
|
|
echo "$(go env GOPATH)/bin" >> "${GITHUB_PATH}"
|
|
|
|
- name: Build nFPM packages
|
|
run: |
|
|
set -euo pipefail
|
|
buildscripts/package-release.sh
|
|
|
|
- name: Generate package SBOMs and signed checksum manifest
|
|
env:
|
|
SYFT_CHECK_FOR_APP_UPDATE: "false"
|
|
run: |
|
|
set -euo pipefail
|
|
packages_dir="dist/packages"
|
|
mapfile -t packages < <(find "${packages_dir}" -maxdepth 1 -type f \
|
|
\( -name '*.rpm' -o -name '*.deb' -o -name '*.apk' \) | sort)
|
|
if [ "${#packages[@]}" -ne 6 ]; then
|
|
echo "Expected six Linux packages, found ${#packages[@]}" >&2
|
|
printf '%s\n' "${packages[@]}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
for package in "${packages[@]}"; do
|
|
syft "${package}" --output "spdx-json=${package}.sbom.json"
|
|
done
|
|
|
|
manifest="${packages_dir}/silo_${PKG_VERSION}_packages_checksums.txt"
|
|
(
|
|
cd "${packages_dir}"
|
|
mapfile -t subjects < <(find . -maxdepth 1 -type f \
|
|
\( -name '*.rpm' -o -name '*.deb' -o -name '*.apk' -o -name '*.sbom.json' \) | sort)
|
|
if [ "${#subjects[@]}" -ne 12 ]; then
|
|
echo "Expected six packages and six SBOMs, found ${#subjects[@]} subjects" >&2
|
|
exit 1
|
|
fi
|
|
sha256sum "${subjects[@]}" | sed 's# \./# #' > "$(basename "${manifest}")"
|
|
)
|
|
cosign sign-blob --bundle="${manifest}.sigstore.json" "${manifest}" --yes
|
|
|
|
- name: Attest downloadable release artifacts
|
|
id: attest-release
|
|
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
|
|
with:
|
|
subject-path: |
|
|
dist/*.tar.gz
|
|
dist/*.zip
|
|
dist/*.sbom.json
|
|
dist/*_checksums.txt
|
|
dist/*.sigstore.json
|
|
dist/packages/*.rpm
|
|
dist/packages/*.deb
|
|
dist/packages/*.apk
|
|
dist/packages/*.sha256sum
|
|
dist/packages/*.sbom.json
|
|
dist/packages/*_checksums.txt
|
|
dist/packages/*.sigstore.json
|
|
|
|
- name: Preserve provenance bundle as a release asset
|
|
env:
|
|
BUNDLE_PATH: ${{ steps.attest-release.outputs.bundle-path }}
|
|
run: |
|
|
set -euo pipefail
|
|
test -s "${BUNDLE_PATH}"
|
|
cp "${BUNDLE_PATH}" "dist/silo_${PKG_VERSION}_provenance.sigstore.json"
|
|
|
|
- name: Upload nFPM packages to Draft release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
mapfile -t files < <(find dist/packages -maxdepth 1 -type f \
|
|
\( -name '*.rpm' -o -name '*.deb' -o -name '*.apk' -o -name '*.sha256sum' \
|
|
-o -name '*.sbom.json' -o -name '*_checksums.txt' -o -name '*.sigstore.json' \) | sort)
|
|
if [ "${#files[@]}" -eq 0 ]; then
|
|
echo "No packages were generated."
|
|
exit 1
|
|
fi
|
|
gh release upload "${RELEASE_TAG}" "${files[@]}" \
|
|
"dist/silo_${PKG_VERSION}_provenance.sigstore.json"
|
|
|
|
- name: Upload dist artifact
|
|
if: always()
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: dist
|
|
path: dist/
|