-
Notifications
You must be signed in to change notification settings - Fork 43
ci: auto-tag release commits and fix publish-svn permissions #424
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| name: Tag on Release Merge | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| - v2 | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| tag: | ||
| runs-on: ubuntu-latest | ||
| if: startsWith(github.event.head_commit.message, 'chore: Release ') | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| fetch-depth: 0 | ||
| # PAT is required so the pushed tag triggers downstream tag-based | ||
| # workflows (publish-svn.yml / publish-svn-v2.yml). Tags pushed with | ||
| # the default GITHUB_TOKEN do not trigger other workflows. | ||
| token: ${{ secrets.GH_PUSH_TOKEN }} | ||
|
|
||
| - uses: onesignal/sdk-shared/.github/actions/setup-git-user@main | ||
|
|
||
| - name: Extract version and push tag | ||
| env: | ||
| MSG: ${{ github.event.head_commit.message }} | ||
| run: | | ||
| SUBJECT=$(printf '%s\n' "$MSG" | head -n 1) | ||
|
|
||
| # Match: "chore: Release X.Y.Z" or "chore: Release X.Y.Z (#NNN)" | ||
| VERSION=$(echo "$SUBJECT" | sed -nE 's/^chore: Release ([0-9]+\.[0-9]+\.[0-9]+)( \(#[0-9]+\))?$/\1/p') | ||
| if [ -z "$VERSION" ]; then | ||
| echo "Commit subject is not a release commit; skipping: $SUBJECT" | ||
| exit 0 | ||
| fi | ||
|
Check warning on line 38 in .github/workflows/tag-on-release-merge.yml
|
||
|
|
||
| TAG="v$VERSION" | ||
| if git rev-parse "refs/tags/$TAG" >/dev/null 2>&1; then | ||
| echo "Tag $TAG already exists; skipping." | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "Tagging $TAG at $GITHUB_SHA" | ||
| git tag "$TAG" "$GITHUB_SHA" | ||
| git push origin "$TAG" | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
🟡 Defense-in-depth gap: the workflow extracts any
X.Y.Zfromchore: Release X.Y.Zand pushesvX.Y.Zwithout verifying that the major matches the branch (main → 3.x, v2 → 2.x). Because theversioninput torelease.yml/release-v2.ymlis a free-form string with no validation, an operator running the wrong Release workflow (e.g. Release (v2) with3.9.1) would land achore: Release 3.9.1commit onv2; this job would then push tagv3.9.1at a v2 commit, andpublish-svn.yml(which has no trunk-version guard, unlike its v2 sibling) would silently deploy v2 source to the v3 trunk on wordpress.org. Consider rejecting when the version major doesn't match the branch (fail if [[ $GITHUB_REF_NAME == main && $VERSION != 3.* ]] || [[ $GITHUB_REF_NAME == v2 && $VERSION != 2.* ]]).Extended reasoning...
What the bug is
tag-on-release-merge.ymltriggers on push to bothmainandv2and extracts the version with this regex:VERSION=$(echo "$SUBJECT" | sed -nE 's/^chore: Release ([0-9]+\.[0-9]+\.[0-9]+)( \(#[0-9]+\))?$/\1/p')It then pushes
v$VERSIONat$GITHUB_SHAwith no cross-check that the major component ofVERSIONmatches the branch the commit landed on. Becausepublish-svn.ymltriggers onv3.*tags andpublish-svn-v2.ymlonv2.*tags, a tag whose major doesn't match its commit's branch routes the wrong source tree to the wrong WordPress.org slot.The code path that triggers it
release.ymlandrelease-v2.ymlboth expose a free-form stringversioninput viaworkflow_dispatchwith no validation:release.ymlhardcodestarget_branch: main;release-v2.ymlhardcodestarget_branch: v2. The branch is locked, but the version isn't validated against it.Step-by-step proof (mistyped version)
version: 3.9.1(typo / wrong workflow).release-v2.ymlcallsprep-release.ymlwithversion=3.9.1, target_branch=v2, which opens a PR titledchore: Release 3.9.1 (#NNN)againstv2. The bump-version step only edits version files on a branch offv2, so the PR diff is small and looks normal.v2. The merge commit subject ischore: Release 3.9.1 (#NNN).tag-on-release-merge.ymlfires on the push tov2. The regex extracts3.9.1. The workflow pushes tagv3.9.1at the v2 head SHA.publish-svn.ymltriggers on thev3.*tag, checks outv3.9.1(= a v2 commit),rsyncs the v2 source tree into/tmp/release-files, andsvn commits it to the v3trunkon wordpress.org as version 3.9.1.The mirror case (Release (v3) with version
2.4.6) lands achore: Release 2.4.6commit onmain, pushesv2.4.6, and triggerspublish-svn-v2.yml. In that direction, theVerify trunk is untouchedstep (publish-svn-v2.yml:110-124) would catch it — but the v3 direction has no equivalent guard.Why existing code doesn't prevent it
target_branchbut notmajor(version) == branch_major.tag-on-release-merge.ymlonly checksstartsWith(message, 'chore: Release ')and regex shape — not major-vs-branch.publish-svn.ymlhas no trunk-version sanity check (only its v2 sibling does), so the v3 direction silently publishes.Addressing the refutation
The refutation argues this requires manually retargeting the auto-PR base branch, which is implausible. That scenario is indeed implausible — but it isn't the only path. The mistyped-
version-input path above doesn't require retargeting anything; it only requires running the wrong of two near-identically-named release workflows or making a typo on the major digit. That's a normal-human-error category (the inputs are free-form strings on workflows namedRelease (v2)andRelease (v3)sitting next to each other in the Actions list). The refutation also claims the payload outcome is technically incorrect because the bump-version branch would carry v3 code; that's exactly right and exactly the problem — v3 code (the entirev3/tree) gets published to wordpress.org under a v2 version number (or vice versa).The refutation's point that the right place to harden against this is the prep workflow (validate version major against target_branch) is fair; either layer works. A guard here is the simpler and more local change since this PR introduces the new automatic-tag step.
Impact
A successful misroute publishes the wrong major's source tree to the WordPress.org plugin directory under the wrong version number. Reverting an SVN trunk commit and a wordpress.org-visible plugin version is operationally painful and user-visible. The v3 direction is unguarded.
How to fix
Two-line guard before pushing the tag:
This converts the silent mis-publish into a CI failure on the tag step, before anything reaches SVN.
Severity
Filing as nit: requires operator error, but the fix is trivial and the blast radius (wrong major published to wordpress.org with no v3-side guard) is non-trivial.