Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
name: release

on:
push:
tags:
- "v*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this only occurs after a tag is created, what benefit does it provide?


# Minimal permissions required by this workflow
permissions:
contents: write # create releases and upload assets
id-token: write # needed for keyless provenance/attestations
attestations: write # record build provenance in the repo's Attestations

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
release:
environment: release
if: startsWith(github.ref, 'refs/tags/')

runs-on: ubuntu-latest
steps:
- name: Check actor access
# Defence in depth: also require multiple approvals from:
# Settings -> Environments -> release -> Deployment protection rules -> Required reviewers
#
if: ${{ !contains( fromJson('["frenchi"]'), github.actor ) }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to tie this to a team, such as @modelcontextprotocol/go-sdk?

# !contains( fromJson('["findleyr", "jba",...]'), github.actor ) }}
run: exit 1

- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # needed to access and verify tags

# TODO(frenchi): Verify tag is signed (GPG/SSH)
# Possible simpler alternative: repo rulesets

# - name: Verify tag is signed (GPG/SSH)
# env:
# GH_TOKEN: ${{ github.token }}
# TAG: ${{ github.ref_name }}
# REPO: ${{ github.repository }}
# run: |
# set -euo pipefail
# obj_type="$(gh api repos/${REPO}/git/ref/tags/${TAG} --jq '.object.type')"
# obj_sha="$(gh api repos/${REPO}/git/ref/tags/${TAG} --jq '.object.sha')"
# echo "Tag ${TAG} type=${obj_type} sha=${obj_sha}"
# if [ "${obj_type}" = "tag" ]; then
# verified="$(gh api repos/${REPO}/git/tags/${obj_sha} --jq '.verification.verified')"
# reason="$(gh api repos/${REPO}/git/tags/${obj_sha} --jq '.verification.reason')"
# else
# verified="$(gh api repos/${REPO}/git/commits/${obj_sha} --jq '.verification.verified')"
# reason="$(gh api repos/${REPO}/git/commits/${obj_sha} --jq '.verification.reason')"
# fi
# echo "verification.verified=${verified} reason=${reason}"
# if [ "${verified}" != "true" ]; then
# echo "Tag ${TAG} is not signed/verified. Aborting release." >&2
# exit 1
# fi

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "^1.23"

- name: Download Go modules (for SBOM resolution)
run: go mod download

# Optional: sigstore/cosign. required for keyless signing at the cost of a (relatively common) dependency on cosign.
# - name: Install Cosign
# uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 #v3.10.0
# Optional: anchore/syft. generate SBOMs, at the cost of a (relatively common) dependency on anchore/sbom-action
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
path: .
format: github-json
output-file: sbom.json
upload-artifact: true
# Zero dep alternative for SBOMs:
#
# Without anchore/sbom-action, we could use actions/go-dependency-submission@v2 to submit
# to the dependency graph and then curl the github API to download the SBOM:
#
# curl -L \
# -H "Accept: application/vnd.github+json" \
# -H "Authorization: Bearer <YOUR-TOKEN>" \
# -H "X-GitHub-Api-Version: 2022-11-28" \
# https://api.github.com/repos/OWNER/REPO/dependency-graph/sboms/SHA
#
# from: https://docs.github.com/en/rest/dependency-graph/sboms?apiVersion=2022-11-28#export-a-software-bill-of-materials-sbom-for-a-repository

- name: Generate SLSA build provenance
uses: actions/attest-build-provenance@v1
with:
subject-path: sbom.json
- name: Create GitHub Release and upload SBOMs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="${{ github.ref_name }}"
TITLE="Release ${TAG}"
gh release create "${TAG}" \
--title "${TITLE}" \
--generate-notes \
sbom.json

- name: Post-release summary
run: |
echo "Release ${{ github.ref_name }} created with SBOMs and provenance attestations."
echo "Environment approvals (if configured) gated this job."