-
-
Notifications
You must be signed in to change notification settings - Fork 32
chore(release): rewrite release pipeline with App auth and cosign signing #79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,133 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| bump: | ||
| description: "Version bump type" | ||
| required: true | ||
| default: "patch" | ||
| type: choice | ||
| options: | ||
| - patch | ||
| - minor | ||
| - major | ||
|
|
||
| concurrency: | ||
| group: release | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| id-token: write | ||
| contents: write | ||
|
|
||
| jobs: | ||
| release: | ||
| if: github.repository == 'bmad-code-org/bmad-builder' && github.ref == 'refs/heads/main' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Generate GitHub App token | ||
| id: app-token | ||
| uses: actions/create-github-app-token@v2 | ||
| with: | ||
| app-id: ${{ secrets.RELEASE_APP_ID }} | ||
| private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} | ||
|
|
||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ steps.app-token.outputs.token }} | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version-file: ".nvmrc" | ||
| cache: "npm" | ||
|
|
||
| - name: Configure git user | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci | ||
|
|
||
| - name: Run validation | ||
| run: | | ||
| npm run format:check | ||
| npm run lint:md | ||
|
|
||
| - name: Bump version | ||
| run: | | ||
| npm version ${{ inputs.bump }} -m "chore(release): v%s [skip ci]" | ||
|
|
||
| - name: Capture new version | ||
| id: version | ||
| run: | | ||
| VERSION=$(node -p "require('./package.json').version") | ||
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | ||
| echo "tag=v${VERSION}" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Push version commit and tag | ||
| run: git push origin main --follow-tags | ||
|
|
||
| - name: Install cosign | ||
| uses: sigstore/cosign-installer@v3 | ||
|
|
||
| - name: Sign tag SHA with cosign (keyless) | ||
| run: | | ||
| TAG="${{ steps.version.outputs.tag }}" | ||
| SHA=$(git rev-parse "${TAG}") | ||
| printf '%s' "${SHA}" > "${TAG}.sha" | ||
| cosign sign-blob --yes \ | ||
| --output-signature "${TAG}.sig" \ | ||
| --output-certificate "${TAG}.pem" \ | ||
| "${TAG}.sha" | ||
|
|
||
| - name: Create GitHub Release | ||
| run: | | ||
| TAG="${{ steps.version.outputs.tag }}" | ||
| VERSION="${{ steps.version.outputs.version }}" | ||
| BODY=$(awk -v ver="$VERSION" ' | ||
| /^## \[/ { if (found) exit; if (index($0, "## [" ver "]")) found=1; next } | ||
| found { print } | ||
| ' CHANGELOG.md) | ||
| if [ -z "$BODY" ]; then | ||
| echo "::error::No CHANGELOG.md entry found for $TAG. Add a '## [${VERSION}] - YYYY-MM-DD' section before releasing." | ||
| exit 1 | ||
| fi | ||
| gh release create "$TAG" \ | ||
| --title "BMad Builder $TAG" \ | ||
| --notes "$BODY" \ | ||
| "${TAG}.sig" \ | ||
| "${TAG}.pem" \ | ||
| "${TAG}.sha" | ||
|
Comment on lines
+69
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate release notes before pushing the version commit and tag. Right now, if the changelog entry is missing or malformed, Lines 93-96 fail only after Line 70 has already pushed 🛠️ Proposed fix - name: Capture new version
id: version
run: |
VERSION=$(node -p "require('./package.json').version")
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
+ - name: Extract release notes
+ run: |
+ TAG="${{ steps.version.outputs.tag }}"
+ VERSION="${{ steps.version.outputs.version }}"
+ awk -v ver="$VERSION" '
+ /^## \[/ { if (found) exit; if (index($0, "## [" ver "]")) found=1; next }
+ found { print }
+ ' CHANGELOG.md > release-notes.md
+ if ! grep -q '[^[:space:]]' release-notes.md; then
+ echo "::error::No CHANGELOG.md entry found for $TAG. Add a '## [${VERSION}] - YYYY-MM-DD' section before releasing."
+ exit 1
+ fi
+
- name: Push version commit and tag
run: git push origin main --follow-tags
- name: Install cosign
uses: sigstore/cosign-installer@v3
@@
- name: Create GitHub Release
run: |
TAG="${{ steps.version.outputs.tag }}"
- VERSION="${{ steps.version.outputs.version }}"
- BODY=$(awk -v ver="$VERSION" '
- /^## \[/ { if (found) exit; if (index($0, "## [" ver "]")) found=1; next }
- found { print }
- ' CHANGELOG.md)
- if [ -z "$BODY" ]; then
- echo "::error::No CHANGELOG.md entry found for $TAG. Add a '## [${VERSION}] - YYYY-MM-DD' section before releasing."
- exit 1
- fi
gh release create "$TAG" \
--title "BMad Builder $TAG" \
- --notes "$BODY" \
+ --notes-file release-notes.md \
"${TAG}.sig" \
"${TAG}.pem" \
"${TAG}.sha"🤖 Prompt for AI Agents |
||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Notify Discord | ||
| if: success() | ||
| continue-on-error: true | ||
| run: | | ||
| set -o pipefail | ||
| source .github/scripts/discord-helpers.sh | ||
| [ -z "$WEBHOOK" ] && exit 0 | ||
| TAG="${{ steps.version.outputs.tag }}" | ||
| RELEASE_URL="${{ github.server_url }}/${{ github.repository }}/releases/tag/${TAG}" | ||
| MSG=$(printf '🛠️ **[BMad Builder %s released](<%s>)**' "$TAG" "$RELEASE_URL" | esc) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In Severity: low 🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage. |
||
| jq -n --arg content "$MSG" '{content: $content}' | curl -sf --retry 2 -X POST "$WEBHOOK" -H "Content-Type: application/json" -d @- | ||
| env: | ||
| WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} | ||
|
|
||
| - name: Summary | ||
| run: | | ||
| TAG="${{ steps.version.outputs.tag }}" | ||
| SHA=$(git rev-parse "${TAG}") | ||
| { | ||
| echo "## Released ${TAG}" | ||
| echo "" | ||
| echo "- **GitHub Release:** https://github.com/${{ github.repository }}/releases/tag/${TAG}" | ||
| echo "- **Tag SHA (cosign-signed):** \`${SHA}\`" | ||
| echo "- **Signature artifacts:** \`${TAG}.sig\`, \`${TAG}.pem\`, \`${TAG}.sha\` attached to the release" | ||
| } >> $GITHUB_STEP_SUMMARY | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In
.github/workflows/release.yaml:78,git rev-parse "${TAG}"will resolve to the tag object SHA if the tag ever becomes annotated, which can make the signed/printed “tag SHA” differ from the commit the tag points to. That mismatch would be confusing for downstream verification and the workflow summary.Other locations where this applies: .github/workflows/release.yaml:123
Severity: medium
Other Locations
.github/workflows/release.yaml:123🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.