Skip to content
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

GitHub Actions workflow hardening #69126

Draft
wants to merge 15 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion .github/setup-node/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ runs:
- name: Get Node.js and npm version
id: node-version
run: |
echo "NODE_VERSION=$(node -v)" >> $GITHUB_OUTPUT
echo "NODE_VERSION=$(node -v)" >> "$GITHUB_OUTPUT"
shell: bash

- name: Cache node_modules
Expand Down
112 changes: 76 additions & 36 deletions .github/workflows/build-plugin-zip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true

# Disable permissions for all available scopes by default.
# Any needed permissions should be configured at the job level.
permissions: {}

jobs:
compute-stable-branches:
name: Compute current and next stable release branches
runs-on: ubuntu-latest
permissions:
contents: read
if: ${{ github.event_name == 'workflow_dispatch' }}
outputs:
current_stable_branch: ${{ steps.get_branches.outputs.current_stable_branch }}
Expand All @@ -36,19 +42,21 @@ jobs:
curl \
-H "Accept: application/vnd.github.v3+json" \
-o latest.json \
"https://api.github.com/repos/${{ github.repository }}/releases/latest"
LATEST_STABLE_TAG=$(jq --raw-output '.tag_name' latest.json)
"https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest"
LATEST_STABLE_TAG="$(jq --raw-output '.tag_name' latest.json)"
IFS='.' read LATEST_STABLE_MAJOR LATEST_STABLE_MINOR LATEST_STABLE_PATCH <<< "${LATEST_STABLE_TAG#v}"
echo "current_stable_branch=release/${LATEST_STABLE_MAJOR}.${LATEST_STABLE_MINOR}" >> $GITHUB_OUTPUT
if [[ ${LATEST_STABLE_MINOR} == "9" ]]; then
echo "next_stable_branch=release/$((LATEST_STABLE_MAJOR + 1)).0" >> $GITHUB_OUTPUT
echo "current_stable_branch=release/${LATEST_STABLE_MAJOR}.${LATEST_STABLE_MINOR}" >> "$GITHUB_OUTPUT"
if [[ "${LATEST_STABLE_MINOR}" == "9" ]]; then
echo "next_stable_branch=release/$((LATEST_STABLE_MAJOR + 1)).0" >> "$GITHUB_OUTPUT"
else
echo "next_stable_branch=release/${LATEST_STABLE_MAJOR}.$((LATEST_STABLE_MINOR + 1))" >> $GITHUB_OUTPUT
echo "next_stable_branch=release/${LATEST_STABLE_MAJOR}.$((LATEST_STABLE_MINOR + 1))" >> "$GITHUB_OUTPUT"
fi

bump-version:
name: Bump version
runs-on: ubuntu-latest
permissions:
contents: write
needs: compute-stable-branches
if: |
github.event_name == 'workflow_dispatch' && (
Expand Down Expand Up @@ -76,31 +84,34 @@ jobs:
with:
token: ${{ secrets.GUTENBERG_TOKEN }}
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: true

- name: Compute old and new version
id: get_version
env:
VERSION: ${{ github.event.inputs.version }}
run: |
OLD_VERSION=$(jq --raw-output '.version' package.json)
echo "old_version=${OLD_VERSION}" >> $GITHUB_OUTPUT
if [[ ${{ github.event.inputs.version }} == 'stable' ]]; then
NEW_VERSION=$(npx semver $OLD_VERSION -i patch)
OLD_VERSION="$(jq --raw-output '.version' package.json)"
echo "old_version=${OLD_VERSION}" >> "$GITHUB_OUTPUT"
if [[ "$VERSION" == 'stable' ]]; then
NEW_VERSION="$(npx semver "$OLD_VERSION" -i patch)"
else
if [[ $OLD_VERSION == *"rc"* ]]; then
NEW_VERSION=$(npx semver $OLD_VERSION -i prerelease)
if [[ "$OLD_VERSION" == *"rc"* ]]; then
NEW_VERSION="$(npx semver "$OLD_VERSION" -i prerelease)"
else
# WordPress version guidelines: If minor is 9, bump major instead.
IFS='.' read -r -a OLD_VERSION_ARRAY <<< "$OLD_VERSION"
if [[ ${OLD_VERSION_ARRAY[1]} == "9" ]]; then
NEW_VERSION="$(npx semver $OLD_VERSION -i major)-rc.1"
NEW_VERSION="$(npx semver "$OLD_VERSION" -i major)-rc.1"
else
NEW_VERSION="$(npx semver $OLD_VERSION -i minor)-rc.1"
NEW_VERSION="$(npx semver "$OLD_VERSION" -i minor)-rc.1"
fi
fi
fi
echo "new_version=${NEW_VERSION}" >> $GITHUB_OUTPUT
echo "new_version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
IFS='.' read -r -a NEW_VERSION_ARRAY <<< "$NEW_VERSION"
RELEASE_BRANCH="release/${NEW_VERSION_ARRAY[0]}.${NEW_VERSION_ARRAY[1]}"
echo "release_branch=${RELEASE_BRANCH}" >> $GITHUB_OUTPUT
echo "release_branch=${RELEASE_BRANCH}" >> "$GITHUB_OUTPUT"

- name: Configure git user name and email
run: |
Expand All @@ -111,51 +122,64 @@ jobs:
if: |
github.event.inputs.version == 'rc' &&
! contains( steps.get_version.outputs.old_version, 'rc' )
run: git checkout -b "${{ steps.get_version.outputs.release_branch }}"
env:
TARGET_BRANCH: ${{ steps.get_version.outputs.release_branch }}
run: git checkout -b "$TARGET_BRANCH"

- name: Switch to release branch
if: |
github.event.inputs.version == 'stable' ||
contains( steps.get_version.outputs.old_version, 'rc' )
env:
TARGET_BRANCH: ${{ steps.get_version.outputs.release_branch }}
run: |
git fetch --depth=1 origin "${{ steps.get_version.outputs.release_branch }}"
git checkout "${{ steps.get_version.outputs.release_branch }}"
git fetch --depth=1 origin "$TARGET_BRANCH"
git checkout "$TARGET_BRANCH"

- name: Update plugin version
env:
VERSION: ${{ steps.get_version.outputs.new_version }}
OLD_VERSION: ${{ steps.get_version.outputs.old_version }}
run: |
cat <<< $(jq --tab --arg version "${VERSION}" '.version = $version' package.json) > package.json
cat <<< $(jq --tab --arg version "${VERSION}" '.version = $version | .packages[""].version = $version' package-lock.json) > package-lock.json
sed -i "s/${{ steps.get_version.outputs.old_version }}/${VERSION}/g" gutenberg.php
cat <<< "$(jq --tab --arg version "${VERSION}" '.version = $version' package.json)" > package.json
cat <<< "$(jq --tab --arg version "${VERSION}" '.version = $version | .packages[""].version = $version' package-lock.json)" > package-lock.json
sed -i "s/${OLD_VERSION}/${VERSION}/g" gutenberg.php

- name: Commit the version bump to the release branch
id: commit_version_bump_to_release_branch
env:
TARGET_BRANCH: ${{ steps.get_version.outputs.release_branch }}
VERSION: ${{ steps.get_version.outputs.new_version }}
run: |
git add gutenberg.php package.json package-lock.json
git commit -m "Bump plugin version to ${{ steps.get_version.outputs.new_version }}"
git push --set-upstream origin "${{ steps.get_version.outputs.release_branch }}"
echo "version_bump_commit=$(git rev-parse --verify --short HEAD)" >> $GITHUB_OUTPUT
git commit -m "Bump plugin version to ${VERSION}"
git push --set-upstream origin "$TARGET_BRANCH"
echo "version_bump_commit=$(git rev-parse --verify --short HEAD)" >> "$GITHUB_OUTPUT"

- name: Fetch trunk
if: ${{ github.ref != 'refs/heads/trunk' }}
run: git fetch --depth=1 origin trunk

- name: Cherry-pick the version bump commit to trunk
id: commit_version_bump_to_trunk
env:
TARGET_BRANCH: ${{ steps.get_version.outputs.release_branch }}
OLD_VERSION: ${{ steps.get_version.outputs.old_version }}
run: |
git checkout trunk
git pull
TRUNK_VERSION=$(jq --raw-output '.version' package.json)
if [[ ${{ steps.get_version.outputs.old_version }} == "$TRUNK_VERSION" ]]; then
git cherry-pick "${{ steps.get_version.outputs.release_branch }}"
TRUNK_VERSION="$(jq --raw-output '.version' package.json)"
if [[ "$OLD_VERSION" == "$TRUNK_VERSION" ]]; then
git cherry-pick "$TARGET_BRANCH"
git push
echo "version_bump_commit=$(git rev-parse --verify --short HEAD)" >> $GITHUB_OUTPUT
echo "version_bump_commit=$(git rev-parse --verify --short HEAD)" >> "$GITHUB_OUTPUT"
fi

build:
name: Build Release Artifact
runs-on: ubuntu-latest
permissions:
contents: read
needs: bump-version
if: |
always() && (
Expand All @@ -172,13 +196,13 @@ jobs:
with:
ref: ${{ needs.bump-version.outputs.release_branch || github.ref }}
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: false

- name: Use desired version of Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
with:
node-version-file: '.nvmrc'
check-latest: true
cache: npm

- name: Build Gutenberg plugin ZIP file
run: ./bin/build-plugin-zip.sh
Expand All @@ -200,7 +224,7 @@ jobs:
MILESTONE="Gutenberg ${VERSION_ARRAY[0]}.${VERSION_ARRAY[1]}"
npm run other:changelog -- --milestone="$MILESTONE" --unreleased > release-notes.txt
sed -ie '1,6d' release-notes.txt
if [[ ${{ needs.bump-version.outputs.new_version }} != *"rc"* ]]; then
if [[ "${VERSION}" != *"rc"* ]]; then
# Include previous RCs' release notes, if any
CHANGELOG_REGEX="=\s[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?\s="
RC_REGEX="=\s${VERSION}(-rc\.[0-9]+)?\s="
Expand All @@ -218,6 +242,8 @@ jobs:
name: Revert version bump if build failed
needs: [bump-version, build]
runs-on: ubuntu-latest
permissions:
contents: write
if: |
always() &&
( needs.build.outputs.job_status == 'failure' ) &&
Expand All @@ -231,6 +257,7 @@ jobs:
ref: ${{ needs.bump-version.outputs.release_branch }}
token: ${{ secrets.GUTENBERG_TOKEN }}
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: true

- name: Configure git user name and email
run: |
Expand All @@ -241,36 +268,45 @@ jobs:
if: |
github.event.inputs.version == 'stable' ||
contains( needs.bump-version.outputs.old_version, 'rc' )
env:
RELEAD_BRANCH_COMMIT: ${{ needs.bump-version.outputs.release_branch_commit }}
RELEASE_BRANCH: ${{ needs.bump-version.outputs.release_branch }}
run: |
git revert --no-edit ${{ needs.bump-version.outputs.release_branch_commit }}
git push --set-upstream origin "${{ needs.bump-version.outputs.release_branch }}"
git revert --no-edit "$RELEAD_BRANCH_COMMIT"
git push --set-upstream origin "$RELEASE_BRANCH"

- name: Delete release branch if it was only just created for the RC
if: |
github.event.inputs.version == 'rc' &&
! contains( needs.bump-version.outputs.old_version, 'rc' )
env:
RELEASE_BRANCH: ${{ needs.bump-version.outputs.release_branch }}
run: |
git push origin :"${{ needs.bump-version.outputs.release_branch }}"
git push origin :"$RELEASE_BRANCH"

- name: Revert version bump on trunk
if: ${{ needs.bump-version.outputs.trunk_commit }}
env:
TRUNK_COMMIT: ${{ needs.bump-version.outputs.trunk_commit }}
run: |
git fetch --depth=2 origin trunk
git checkout trunk
git revert --no-edit ${{ needs.bump-version.outputs.trunk_commit }}
git revert --no-edit "$TRUNK_COMMIT"
git push --set-upstream origin trunk

create-release:
name: Create Release Draft and Attach Asset
needs: [bump-version, build]
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Set Release Version
id: get_release_version
env:
VERSION: ${{ needs.bump-version.outputs.new_version }}
run: echo "version=$(echo $VERSION | cut -d / -f 3 | sed 's/-rc./ RC/' )" >> $GITHUB_OUTPUT
run: echo "version=$(echo "$VERSION" | cut -d / -f 3 | sed 's/-rc./ RC/' )" >> "$GITHUB_OUTPUT"

- name: Download Plugin Zip Artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
Expand Down Expand Up @@ -309,6 +345,8 @@ jobs:
npm-publish:
name: Publish WordPress packages to npm
runs-on: ubuntu-latest
permissions:
contents: read
environment: WordPress packages
needs: [bump-version, build]
if: ${{ endsWith( needs.bump-version.outputs.new_version, '-rc.1' ) }}
Expand All @@ -319,6 +357,7 @@ jobs:
path: main
ref: trunk
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: false

- name: Checkout (for publishing)
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Expand All @@ -328,6 +367,7 @@ jobs:
ref: trunk
token: ${{ secrets.GUTENBERG_TOKEN }}
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: false

- name: Configure git user name and email (for publishing)
run: |
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/bundle-size.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,24 @@ concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true

# Disable permissions for all available scopes by default.
# Any needed permissions should be configured at the job level.
permissions: {}

jobs:
build:
name: Check
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 1
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: false

- name: Use desired version of Node.js
uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/check-backport-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,25 @@ on:
- 'packages/**/*.php'
- '!packages/block-library/**'
- '!packages/e2e-tests/**'

# Disable permissions for all available scopes by default.
# Any needed permissions should be configured at the job level.
permissions: {}

jobs:
check:
name: Check for a Core backport changelog entry
runs-on: ubuntu-latest
permissions:
contents: read
if: ${{ !contains(github.event.pull_request.labels.*.name, 'No Core Sync Required') && !contains(github.event.pull_request.labels.*.name, 'Backport from WordPress Core') }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ github.event.pull_request.head.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
persist-credentials: false

- name: Check the changelog folder
env:
PR_NUMBER: ${{ github.event.number }}
Expand All @@ -44,7 +53,7 @@ jobs:
exit 1
fi

core_pr_number=$(basename "${changelog_file}" .md)
core_pr_number="$(basename "${changelog_file}" .md)"
core_pr_url="https://github\.com/WordPress/wordpress-develop/pull/${core_pr_number}"

# Confirm that the entry has the correct core backport PR URL.
Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/check-components-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ on:
- '!packages/components/src/**/*.native.js'
- '!packages/components/src/**/*.native.scss'
- '!packages/components/src/**/react-native-*'

# Disable permissions for all available scopes by default.
# Any needed permissions should be configured at the job level.
permissions: {}

jobs:
check:
name: Check CHANGELOG diff
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: 'Get PR commit count'
run: echo "PR_COMMIT_COUNT=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_ENV}"
Expand All @@ -28,17 +35,19 @@ jobs:
repository: ${{ github.event.pull_request.head.repo.full_name }}
fetch-depth: ${{ env.PR_COMMIT_COUNT }}
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
persist-credentials: false
- name: 'Fetch relevant history from origin'
run: git fetch origin ${{ github.event.pull_request.base.ref }}
run: git fetch origin "$GITHUB_BASE_REF"
- name: Check CHANGELOG status
env:
PR_NUMBER: ${{ github.event.number }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
changelog_path="packages/components/CHANGELOG.md"
optional_check_notice="This isn't a required check, so if you think your changes are small enough that they don't warrant a CHANGELOG entry, please go ahead and merge without one."

# Fail if the PR doesn't touch the changelog
if git diff --quiet ${{ github.event.pull_request.base.sha }} HEAD -- "$changelog_path"; then
if git diff --quiet "$HEAD_SHA" HEAD -- "$changelog_path"; then
echo "Please add a CHANGELOG entry to $changelog_path"
echo
echo "${optional_check_notice}"
Expand Down
Loading
Loading