diff --git a/.github/setup-node/action.yml b/.github/setup-node/action.yml index a17adfe5f5007..5fc76a6bc2d12 100644 --- a/.github/setup-node/action.yml +++ b/.github/setup-node/action.yml @@ -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 diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index 281146b63f290..6f0e36fb55feb 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -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 }} @@ -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' && ( @@ -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: | @@ -111,31 +122,39 @@ 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' }} @@ -143,19 +162,24 @@ jobs: - 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() && ( @@ -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 @@ -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=" @@ -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' ) && @@ -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: | @@ -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 @@ -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' ) }} @@ -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 @@ -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: | diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index b967157836a4d..77cc5284423a4 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -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 diff --git a/.github/workflows/check-backport-changelog.yml b/.github/workflows/check-backport-changelog.yml index 48fb56b425be3..b5fa851729355 100644 --- a/.github/workflows/check-backport-changelog.yml +++ b/.github/workflows/check-backport-changelog.yml @@ -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 }} @@ -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. diff --git a/.github/workflows/check-components-changelog.yml b/.github/workflows/check-components-changelog.yml index 373a782d5d6dd..d39097a4a13c5 100644 --- a/.github/workflows/check-components-changelog.yml +++ b/.github/workflows/check-components-changelog.yml @@ -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}" @@ -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}" diff --git a/.github/workflows/cherry-pick-wp-release.yml b/.github/workflows/cherry-pick-wp-release.yml index 14bee71c90c90..b6393f8eff8b7 100644 --- a/.github/workflows/cherry-pick-wp-release.yml +++ b/.github/workflows/cherry-pick-wp-release.yml @@ -16,9 +16,17 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: false +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: cherry-pick: runs-on: ubuntu-latest + permissions: + contents: write + issues: write + pull-requests: read # When in the context of a PR, ensure the PR is merged. if: github.event.pull_request == null || github.event.pull_request.merged == true steps: @@ -74,6 +82,7 @@ jobs: with: token: ${{ secrets.GUTENBERG_TOKEN }} fetch-depth: 0 + persist-credentials: false - name: Set up Git if: env.cherry_pick == 'true' @@ -85,20 +94,20 @@ jobs: id: cherry-pick if: env.cherry_pick == 'true' run: | - TARGET_BRANCH="wp/${{ env.version }}" - COMMIT_SHA="${{ env.commit_sha }}" + TARGET_BRANCH="wp/${version}" + COMMIT_SHA="${commit_sha}" echo "Target branch: $TARGET_BRANCH" echo "Commit SHA: $COMMIT_SHA" - git checkout $TARGET_BRANCH - git cherry-pick $COMMIT_SHA || echo "cherry-pick-failed" > result + git checkout "$TARGET_BRANCH" + git cherry-pick "$COMMIT_SHA" || echo "cherry-pick-failed" > result if [ -f result ] && grep -q "cherry-pick-failed" result; then - echo "conflict=true" >> $GITHUB_ENV + echo "conflict=true" >> "$GITHUB_ENV" git cherry-pick --abort else - CHERRY_PICK_SHA=$(git rev-parse HEAD) - echo "conflict=false" >> $GITHUB_ENV - echo "cherry_pick_sha=$CHERRY_PICK_SHA" >> $GITHUB_ENV - git push origin $TARGET_BRANCH + CHERRY_PICK_SHA="$(git rev-parse HEAD)" + echo "conflict=false" >> "$GITHUB_ENV" + echo "cherry_pick_sha=$CHERRY_PICK_SHA" >> "$GITHUB_ENV" + git push origin "$TARGET_BRANCH" fi - name: Remove cherry-pick label diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index 1cb40466abe1e..2caed50f86c62 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -12,10 +12,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: checks: name: Checks w/Node.js ${{ matrix.node }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: fail-fast: false @@ -27,6 +33,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml index ea85a8949573f..07ed1a81f3de9 100644 --- a/.github/workflows/end2end-test.yml +++ b/.github/workflows/end2end-test.yml @@ -15,10 +15,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: e2e-playwright: name: Playwright - ${{ matrix.part }} runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: fail-fast: false @@ -30,6 +36,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node @@ -72,6 +79,7 @@ jobs: if: ${{ !cancelled() }} needs: [e2e-playwright] runs-on: ubuntu-latest + permissions: {} outputs: has-flaky-test-report: ${{ !!steps.merge-flaky-tests-reports.outputs.artifact-id }} steps: @@ -99,6 +107,10 @@ jobs: needs: [merge-artifacts] if: ${{ needs.merge-artifacts.outputs.has-flaky-test-report == 'true' }} runs-on: ubuntu-latest + permissions: + contents: read + issues: write + pull-requests: write steps: # Checkout defaults to using the branch which triggered the event, which # isn't necessarily `trunk` (e.g. in the case of a merge). @@ -106,6 +118,7 @@ jobs: with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - uses: actions/download-artifact@v4.1.8 # Don't fail the job if there isn't any flaky tests report. diff --git a/.github/workflows/enforce-pr-labels.yml b/.github/workflows/enforce-pr-labels.yml index 7493459a6ff35..b7f0c27a71633 100644 --- a/.github/workflows/enforce-pr-labels.yml +++ b/.github/workflows/enforce-pr-labels.yml @@ -2,6 +2,11 @@ name: Enforce labels on Pull Request on: pull_request_target: types: [labeled, unlabeled, ready_for_review, review_requested] + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: type-related-labels: runs-on: ubuntu-latest diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index c4c5eeba9c51a..d674ee2626b29 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -1,14 +1,22 @@ name: 'Validate Gradle Wrapper' on: [push, pull_request] +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: validation: name: 'Validation' runs-on: ubuntu-latest + permissions: + contents: read steps: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false + - name: Validate checksums uses: gradle/actions/wrapper-validation@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2 diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 4a5b576b424b5..78352971755d6 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -23,11 +23,17 @@ 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: performance: timeout-minutes: 60 name: Run performance tests runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' }} env: WP_ARTIFACTS_PATH: ${{ github.workspace }}/artifacts @@ -36,6 +42,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node @@ -49,7 +56,7 @@ jobs: - name: Compare performance with base branch if: github.event_name == 'pull_request' - run: ./bin/plugin/cli.js perf $GITHUB_SHA ${{ github.base_ref }} --tests-branch $GITHUB_SHA + run: ./bin/plugin/cli.js perf "$GITHUB_SHA" "$GITHUB_BASE_REF" --tests-branch "$GITHUB_SHA" - name: Compare performance with current WordPress Core and previous Gutenberg versions if: github.event_name == 'release' @@ -61,10 +68,10 @@ jobs: CURRENT_RELEASE_BRANCH="release/${PLUGIN_VERSION_ARRAY[0]}.${PLUGIN_VERSION_ARRAY[1]}" PREVIOUS_VERSION_BASE_10=$((PLUGIN_VERSION_ARRAY[0] * 10 + PLUGIN_VERSION_ARRAY[1] - 1)) PREVIOUS_RELEASE_BRANCH="release/$((PREVIOUS_VERSION_BASE_10 / 10)).$((PREVIOUS_VERSION_BASE_10 % 10))" - WP_VERSION=$(awk -F ': ' '/^Tested up to/{print $2}' readme.txt) + WP_VERSION="$(awk -F ': ' '/^Tested up to/{print $2}' readme.txt)" IFS=. read -ra WP_VERSION_ARRAY <<< "$WP_VERSION" WP_MAJOR="${WP_VERSION_ARRAY[0]}.${WP_VERSION_ARRAY[1]}" - ./bin/plugin/cli.js perf "wp/$WP_MAJOR" "$PREVIOUS_RELEASE_BRANCH" "$CURRENT_RELEASE_BRANCH" --tests-branch $GITHUB_SHA --wp-version "$WP_MAJOR" + ./bin/plugin/cli.js perf "wp/$WP_MAJOR" "$PREVIOUS_RELEASE_BRANCH" "$CURRENT_RELEASE_BRANCH" --tests-branch "$GITHUB_SHA" --wp-version "$WP_MAJOR" - name: Compare performance with base branch if: github.event_name == 'push' @@ -72,10 +79,10 @@ jobs: # The current one is c7722262e65a3f4d0f1a2d1ad29eccb2069509e4 and it needs to be updated every WP major release. # It is used as a base comparison point to avoid fluctuation in the performance metrics. run: | - WP_VERSION=$(awk -F ': ' '/^Tested up to/{print $2}' readme.txt) + WP_VERSION="$(awk -F ': ' '/^Tested up to/{print $2}' readme.txt)" IFS=. read -ra WP_VERSION_ARRAY <<< "$WP_VERSION" WP_MAJOR="${WP_VERSION_ARRAY[0]}.${WP_VERSION_ARRAY[1]}" - ./bin/plugin/cli.js perf $GITHUB_SHA c7722262e65a3f4d0f1a2d1ad29eccb2069509e4 --tests-branch $GITHUB_SHA --wp-version "$WP_MAJOR" + ./bin/plugin/cli.js perf "$GITHUB_SHA" c7722262e65a3f4d0f1a2d1ad29eccb2069509e4 --tests-branch "$GITHUB_SHA" --wp-version "$WP_MAJOR" - name: Compare performance with custom branches if: github.event_name == 'workflow_dispatch' @@ -83,10 +90,10 @@ jobs: BRANCHES: ${{ github.event.inputs.branches }} WP_VERSION: ${{ github.event.inputs.wpversion }} run: | - ./bin/plugin/cli.js perf $(echo $BRANCHES | tr ',' ' ') --tests-branch $GITHUB_SHA --wp-version "$WP_VERSION" + ./bin/plugin/cli.js perf "$(echo "$BRANCHES" | tr ',' ' ')" --tests-branch "$GITHUB_SHA" --wp-version "$WP_VERSION" - name: Add workflow summary - run: cat ${{ env.WP_ARTIFACTS_PATH }}/summary.md >> $GITHUB_STEP_SUMMARY + run: cat "${WP_ARTIFACTS_PATH}/summary.md" >> "$GITHUB_STEP_SUMMARY" - name: Archive performance results if: success() @@ -100,8 +107,8 @@ jobs: env: CODEHEALTH_PROJECT_TOKEN: ${{ secrets.CODEHEALTH_PROJECT_TOKEN }} run: | - COMMITTED_AT=$(git show -s $GITHUB_SHA --format="%cI") - ./bin/log-performance-results.js $CODEHEALTH_PROJECT_TOKEN trunk $GITHUB_SHA c7722262e65a3f4d0f1a2d1ad29eccb2069509e4 $COMMITTED_AT + COMMITTED_AT="$(git show -s "$GITHUB_SHA" --format="%cI")" + ./bin/log-performance-results.js "$CODEHEALTH_PROJECT_TOKEN" trunk "$GITHUB_SHA" c7722262e65a3f4d0f1a2d1ad29eccb2069509e4 "$COMMITTED_AT" - name: Archive debug artifacts (screenshots, HTML snapshots) uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 diff --git a/.github/workflows/publish-npm-packages.yml b/.github/workflows/publish-npm-packages.yml index 7a354ed819dfc..00dbd25dadfaa 100644 --- a/.github/workflows/publish-npm-packages.yml +++ b/.github/workflows/publish-npm-packages.yml @@ -23,10 +23,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: release: name: Release - ${{ github.event.inputs.release_type }} runs-on: ubuntu-latest + permissions: + contents: read environment: WordPress packages steps: - name: Checkout (for CLI) @@ -36,6 +42,7 @@ jobs: path: cli ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Checkout (for publishing) if: ${{ github.event.inputs.release_type != 'wp' }} @@ -46,6 +53,7 @@ jobs: ref: trunk token: ${{ secrets.GUTENBERG_TOKEN }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Checkout (for publishing WP major version) if: ${{ github.event.inputs.release_type == 'wp' && github.event.inputs.wp_version }} @@ -58,6 +66,7 @@ jobs: fetch-depth: 999 token: ${{ secrets.GUTENBERG_TOKEN }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Configure git user name and email (for publishing) run: | @@ -104,6 +113,7 @@ jobs: run: | cd publish npm ci - npx lerna publish patch --dist-tag wp-${{ github.event.inputs.wp_version }} --no-private --yes --no-verify-access + npx lerna publish patch --dist-tag "wp-$WP_VERSION" --no-private --yes --no-verify-access env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + WP_VERSION: ${{ github.event.inputs.wp_version }} diff --git a/.github/workflows/pull-request-automation.yml b/.github/workflows/pull-request-automation.yml index e1a3defc641aa..c77041ec78e4b 100644 --- a/.github/workflows/pull-request-automation.yml +++ b/.github/workflows/pull-request-automation.yml @@ -4,9 +4,17 @@ on: push: name: Pull request automation +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: pull-request-automation: runs-on: ubuntu-latest + permissions: + contents: read + issues: write + pull-requests: write if: ${{ github.repository == 'WordPress/gutenberg' }} steps: @@ -16,6 +24,7 @@ jobs: with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node diff --git a/.github/workflows/reusable-workflow-lint.yml b/.github/workflows/reusable-workflow-lint.yml new file mode 100644 index 0000000000000..2fa177b3f92ab --- /dev/null +++ b/.github/workflows/reusable-workflow-lint.yml @@ -0,0 +1,115 @@ +name: Lint GitHub Actions workflows +on: + workflow_call: + +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + +jobs: + # Runs the actionlint GitHub Action workflow file linter. + # + # This helps guard against common mistakes including strong type checking for expressions (${{ }}), security checks, + # `run:` script checking, glob syntax validation, and more. + # + # Performs the following steps: + # - Checks out the repository. + # - Runs actionlint. + actionlint: + name: Run actionlint + runs-on: ubuntu-24.04 + permissions: + contents: read + timeout-minutes: 5 + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + + # actionlint is static checker for GitHub Actions workflow files. + # See https://github.com/rhysd/actionlint. + - name: Run actionlint + uses: docker://rhysd/actionlint:1.7.7 + with: + args: "-color -verbose" + + octoscan: + name: Octoscan + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + timeout-minutes: 10 + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Run octoscan + id: octoscan + uses: synacktiv/action-octoscan@6b1cf2343893dfb9e5f75652388bd2dc83f456b0 # v1.0.0 + with: + filter_triggers: '' + # dangerous-write: Valid but ignored because we have to use these writes + # dangerous-checkout: Three false positives + # local-action: Not much we can do about this + disable_rules: dangerous-write,dangerous-checkout,local-action + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 + with: + sarif_file: ${{steps.octoscan.outputs.sarif_output}} + category: octoscan + + zizmor: + name: Zizmor + runs-on: ubuntu-latest + permissions: + security-events: write + actions: read + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Install the latest version of uv + uses: astral-sh/setup-uv@b5f58b2abc5763ade55e4e9d0fe52cd1ff7979ca # v5.2.1 + + # https://github.com/woodruffw/zizmor + - name: Run zizmor + run: uvx zizmor@1.3.1 --format sarif . > results.sarif + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 + with: + sarif_file: results.sarif + category: zizmor + + poutine: + name: Poutine + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Run Poutine + uses: boostsecurityio/poutine-action@84c0a0d32e8d57ae12651222be1eb15351429228 # v0.15.2 + + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9 + with: + sarif_file: results.sarif + category: poutine diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index 4989239286462..26fe9e675a203 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -12,9 +12,15 @@ 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: test: runs-on: macos-13 + permissions: + contents: read if: false #if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: @@ -27,6 +33,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Use desired version of Java uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0 diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 4d6b310e60f97..10ff4b98ede4f 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -12,9 +12,15 @@ 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: test: runs-on: macos-13 + permissions: + contents: read if: false #if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: @@ -27,6 +33,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - uses: ruby/setup-ruby@1287d2b408066abada82d5ad1c63652e758428d9 # v1.214.0 with: diff --git a/.github/workflows/stale-issue-gardening.yml b/.github/workflows/stale-issue-gardening.yml index 6b8c7e82d1ca7..075dd43adc6ac 100644 --- a/.github/workflows/stale-issue-gardening.yml +++ b/.github/workflows/stale-issue-gardening.yml @@ -4,10 +4,17 @@ on: schedule: - cron: '0 0 * * *' +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: issue-gardening: name: ${{ matrix.name }} runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write if: ${{ github.repository == 'WordPress/gutenberg' }} strategy: matrix: diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 9281158aab833..259225e523d8b 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -15,16 +15,23 @@ 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: check: name: All runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: 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 diff --git a/.github/workflows/storybook-check.yml b/.github/workflows/storybook-check.yml index dd710f9674712..734b0e111153c 100644 --- a/.github/workflows/storybook-check.yml +++ b/.github/workflows/storybook-check.yml @@ -9,9 +9,15 @@ 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: check: runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: @@ -19,6 +25,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index 4af4934cf0325..1dd951e05a1d2 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -5,9 +5,15 @@ on: branches: - trunk +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: deploy: runs-on: ubuntu-latest + permissions: + contents: write if: ${{ github.repository == 'WordPress/gutenberg' }} steps: @@ -16,6 +22,7 @@ jobs: with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node diff --git a/.github/workflows/sync-assets-to-plugin-repo.yml b/.github/workflows/sync-assets-to-plugin-repo.yml index c841b3ffc7957..356b4f15c3910 100644 --- a/.github/workflows/sync-assets-to-plugin-repo.yml +++ b/.github/workflows/sync-assets-to-plugin-repo.yml @@ -7,10 +7,16 @@ on: paths: - assets/** +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: sync-assets: name: Sync assets to WordPress.org plugin repo runs-on: ubuntu-latest + permissions: + contents: read environment: wp.org plugin env: PLUGIN_REPO_URL: 'https://plugins.svn.wordpress.org/gutenberg' @@ -33,6 +39,7 @@ jobs: assets show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} path: git + persist-credentials: false - name: Copy files from git checkout to svn working copy run: cp -R git/assets/* assets diff --git a/.github/workflows/sync-backport-changelog.yml b/.github/workflows/sync-backport-changelog.yml index e530ca667de3d..6d38d218a7cd1 100644 --- a/.github/workflows/sync-backport-changelog.yml +++ b/.github/workflows/sync-backport-changelog.yml @@ -7,10 +7,17 @@ on: issues: types: [labeled] +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: sync-backport-changelog: name: Sync Core Backport Issue runs-on: ubuntu-latest + permissions: + contents: read + issues: write if: > github.event_name == 'push' || ( @@ -23,6 +30,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 2 # Fetch the last two commits to compare changes + persist-credentials: false - name: Check for changes in backport-changelog if: github.event_name == 'push' run: | diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index b5c5e2255da5e..809a4369246d8 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -19,10 +19,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: unit-js: name: JavaScript (Node.js ${{ matrix.node }}) ${{ matrix.shard }} runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: fail-fast: false @@ -35,6 +41,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node @@ -52,16 +59,20 @@ jobs: run: npx lerna run build - name: Running the tests + env: + MAXWORKERS: ${{ steps.cpu-cores.outputs.count }} run: | npm run test:unit -- \ --ci \ - --maxWorkers="${{ steps.cpu-cores.outputs.count }}" \ + --maxWorkers="$MAXWORKERS" \ --shard="${{ matrix.shard }}" \ --cacheDirectory="$HOME/.jest-cache" unit-js-date: name: JavaScript Date Tests (Node.js ${{ matrix.node }}) runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: fail-fast: false @@ -73,6 +84,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node @@ -90,11 +102,14 @@ jobs: run: npx lerna run build - name: Run the date tests - run: npm run test:unit:date -- --ci --maxWorkers=${{ steps.cpu-cores.outputs.count }} --cacheDirectory="$HOME/.jest-cache" + env: + MAXWORKERS: ${{ steps.cpu-cores.outputs.count }} + run: npm run test:unit:date -- --ci --maxWorkers="$MAXWORKERS" --cacheDirectory="$HOME/.jest-cache" compute-previous-wordpress-version: name: Compute previous WordPress version runs-on: ubuntu-latest + permissions: {} outputs: previous-wordpress-version: ${{ steps.get-previous-wordpress-version.outputs.previous-wordpress-version }} @@ -106,24 +121,27 @@ jobs: -H "Accept: application/json" \ -o versions.json \ "http://api.wordpress.org/core/stable-check/1.0/" - LATEST_WP_VERSION=$(jq --raw-output 'with_entries(select(.value=="latest"))|keys[]' versions.json) + LATEST_WP_VERSION="$(jq --raw-output 'with_entries(select(.value=="latest"))|keys[]' versions.json)" IFS='.' read LATEST_WP_MAJOR LATEST_WP_MINOR LATEST_WP_PATCH <<< "${LATEST_WP_VERSION}" - if [[ ${LATEST_WP_MINOR} == "0" ]]; then + if [[ "${LATEST_WP_MINOR}" == "0" ]]; then PREVIOUS_WP_SERIES="$((LATEST_WP_MAJOR - 1)).9" else PREVIOUS_WP_SERIES="${LATEST_WP_MAJOR}.$((LATEST_WP_MINOR - 1))" fi - PREVIOUS_WP_VERSION=$(jq --raw-output --arg series "${PREVIOUS_WP_SERIES}" 'with_entries(select(.key|startswith($series)))|keys[-1]' versions.json) - echo "previous-wordpress-version=${PREVIOUS_WP_VERSION}" >> $GITHUB_OUTPUT + PREVIOUS_WP_VERSION="$(jq --raw-output --arg series "${PREVIOUS_WP_SERIES}" 'with_entries(select(.key|startswith($series)))|keys[-1]' versions.json)" + echo "previous-wordpress-version=${PREVIOUS_WP_VERSION}" >> "$GITHUB_OUTPUT" rm versions.json build-assets: name: Build JavaScript assets for PHP unit tests runs-on: ubuntu-latest + permissions: + contents: read steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node @@ -143,6 +161,8 @@ jobs: name: PHP ${{ matrix.php }}${{ matrix.multisite && ' multisite' || '' }}${{ matrix.wordpress != '' && format( ' (WP {0}) ', matrix.wordpress ) || '' }} on ubuntu-latest needs: [compute-previous-wordpress-version, build-assets] runs-on: ubuntu-latest + permissions: + contents: read timeout-minutes: 20 if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} strategy: @@ -176,6 +196,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Setup Node.js and install dependencies uses: ./.github/setup-node @@ -258,14 +279,14 @@ jobs: run: | # Note: relies on PHPUnit execution to fail on test failure. # Extract the number of executed tests from the log file. - if ! num_tests=$(grep -Eo 'OK \([0-9]+ tests' phpunit.log) ; then - if ! num_tests=$(grep -Eo 'Tests: [0-9]+, Assertions:' phpunit.log) ; then + if ! num_tests="$(grep -Eo 'OK \([0-9]+ tests' phpunit.log)" ; then + if ! num_tests="$(grep -Eo 'Tests: [0-9]+, Assertions:' phpunit.log)" ; then echo "PHPUnit failed or did not run. Check the PHPUnit output in the previous step to debug." && exit 1 fi fi # Extract just the number of tests from the string. - num_tests=$(echo "$num_tests" | grep -Eo '[0-9]+') - if [ $num_tests -lt 500 ] ; then + num_tests="$(echo "$num_tests" | grep -Eo '[0-9]+')" + if [ "$num_tests" -lt 500 ] ; then echo "Only $num_tests tests passed, which is much fewer than expected." && exit 1 fi echo "$num_tests tests passed." @@ -273,6 +294,8 @@ jobs: phpcs: name: PHP coding standards runs-on: ubuntu-latest + permissions: + contents: read timeout-minutes: 20 if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} @@ -281,6 +304,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Set up PHP uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0 @@ -293,7 +317,7 @@ jobs: # http://man7.org/linux/man-pages/man1/date.1.html - name: "Get last Monday's date" id: get-date - run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> $GITHUB_OUTPUT + run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> "$GITHUB_OUTPUT" - name: Cache PHPCS scan cache uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 @@ -309,7 +333,7 @@ jobs: custom-cache-suffix: ${{ steps.get-date.outputs.date }} - name: Make Composer packages available globally - run: echo "${PWD}/vendor/bin" >> $GITHUB_PATH + run: echo "${PWD}/vendor/bin" >> "$GITHUB_PATH" - name: Run PHPCS on all Gutenberg files id: phpcs-gutenberg @@ -326,6 +350,7 @@ jobs: unit-php: name: PHP runs-on: ubuntu-latest + permissions: {} needs: [test-php, phpcs] if: ${{ always() }} steps: @@ -344,6 +369,8 @@ jobs: mobile-unit-js: name: Mobile runs-on: ubuntu-latest + permissions: + contents: read if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: @@ -351,6 +378,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: false - name: Determine the number of CPU cores uses: SimenB/github-actions-cpu-cores@97ba232459a8e02ff6121db9362b09661c875ab8 # v2.0.0 @@ -366,4 +394,6 @@ jobs: run: npx lerna run build - name: Running the tests - run: npm run test:native -- --ci --maxWorkers=${{ steps.cpu-cores.outputs.count }} --cacheDirectory="$HOME/.jest-cache" + env: + MAXWORKERS: ${{ steps.cpu-cores.outputs.count }} + run: npm run test:native -- --ci --maxWorkers="$MAXWORKERS" --cacheDirectory="$HOME/.jest-cache" diff --git a/.github/workflows/upload-release-to-plugin-repo.yml b/.github/workflows/upload-release-to-plugin-repo.yml index 7d2c780599cdd..36f5eb185c123 100644 --- a/.github/workflows/upload-release-to-plugin-repo.yml +++ b/.github/workflows/upload-release-to-plugin-repo.yml @@ -4,10 +4,15 @@ on: release: types: [published] +# Disable permissions for all available scopes by default. +# Any needed permissions should be configured at the job level. +permissions: {} + jobs: compute-should-update-trunk: name: Decide if trunk or tag runs-on: ubuntu-latest + permissions: {} # Skip this job if the release is a release candidate. This will in turn skip # the upload jobs, which are only relevant for non-RC releases. # We first check if the release is a prerelease, and then if the ref contains @@ -25,15 +30,15 @@ jobs: run: | latest_version_in_core_repo=$(curl -s 'https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request\[slug\]=gutenberg' | jq -r '.version') echo "Latest Core Repo version: $latest_version_in_core_repo" - echo "version=$latest_version_in_core_repo" >> $GITHUB_OUTPUT + echo "version=$latest_version_in_core_repo" >> "$GITHUB_OUTPUT" - name: Decide if it is a trunk or tag update id: compute_should_update_trunk env: GITHUB_REF: ${{ github.ref }} + LATEST_VERSION: ${{ steps.compute_latest_version_in_core_repo.outputs.version }} run: | latestPublishedVersion=$(echo "$GITHUB_REF" | sed -E 's/refs\/tags\/(v?)([0-9.]+)/\2/') - latestVersionInCoreRepo="${{ steps.compute_latest_version_in_core_repo.outputs.version }}" # Determines if the first version string is greater than the second version string. # @@ -55,16 +60,17 @@ jobs: # than the version currently published in the WP plugins repo. If not, then it # will upload it as a new tag. shouldUpdateTrunk=false - if is_first_version_greater_than_second "$latestPublishedVersion" "$latestVersionInCoreRepo"; then + if is_first_version_greater_than_second "$latestPublishedVersion" "$LATEST_VERSION"; then shouldUpdateTrunk=true fi echo "Should update trunk: $shouldUpdateTrunk" - echo "should_update_trunk=$shouldUpdateTrunk" >> $GITHUB_OUTPUT + echo "should_update_trunk=$shouldUpdateTrunk" >> "$GITHUB_OUTPUT" get-release-branch: name: Get release branch name runs-on: ubuntu-latest + permissions: {} outputs: release_branch: ${{ steps.get_release_branch.outputs.release_branch }} @@ -76,11 +82,13 @@ jobs: run: | IFS='.' read -r -a VERSION_ARRAY <<< "${TAG#v}" RELEASE_BRANCH="release/${VERSION_ARRAY[0]}.${VERSION_ARRAY[1]}" - echo "release_branch=${RELEASE_BRANCH}" >> $GITHUB_OUTPUT + echo "release_branch=${RELEASE_BRANCH}" >> "$GITHUB_OUTPUT" update-changelog: name: Update Changelog on ${{ matrix.branch }} branch runs-on: ubuntu-latest + permissions: + contents: write if: | github.event.release.assets[0] needs: get-release-branch @@ -101,6 +109,7 @@ jobs: ref: ${{ matrix.branch }} token: ${{ secrets.GUTENBERG_TOKEN }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} + persist-credentials: true - name: Update the Changelog to include the release notes run: | @@ -135,6 +144,8 @@ jobs: git config user.email gutenberg@wordpress.org - name: Commit the Changelog update + env: + TARGET_BRANCH: ${{ matrix.branch }} run: | git add changelog.txt # Remove files that are not meant to be committed @@ -143,7 +154,7 @@ jobs: # Only attempt to commit changelog if it has been modified. if ! git diff-index --quiet HEAD --; then git commit -m "Update Changelog for ${TAG#v}" - git push --set-upstream origin "${{ matrix.branch }}" + git push --set-upstream origin "$TARGET_BRANCH" fi - name: Upload Changelog artifact @@ -155,6 +166,7 @@ jobs: upload: name: Publish as trunk (and tag) runs-on: ubuntu-latest + permissions: {} environment: wp.org plugin needs: [compute-should-update-trunk, update-changelog] if: | @@ -184,7 +196,7 @@ jobs: env: PLUGIN_URL: ${{ github.event.release.assets[0].browser_download_url }} run: | - curl -L -o gutenberg.zip $PLUGIN_URL + curl -L -o gutenberg.zip "$PLUGIN_URL" unzip gutenberg.zip -d trunk rm gutenberg.zip @@ -214,6 +226,7 @@ jobs: upload-tag: name: Publish as tag runs-on: ubuntu-latest + permissions: {} environment: wp.org plugin needs: [compute-should-update-trunk, update-changelog] if: | @@ -235,7 +248,7 @@ jobs: PLUGIN_URL: ${{ github.event.release.assets[0].browser_download_url }} run: | # do the magic here - curl -L -o gutenberg.zip $PLUGIN_URL + curl -L -o gutenberg.zip "$PLUGIN_URL" unzip gutenberg.zip -d "$VERSION" rm gutenberg.zip diff --git a/.github/workflows/workflow-lint.yml b/.github/workflows/workflow-lint.yml new file mode 100644 index 0000000000000..6789acb03785f --- /dev/null +++ b/.github/workflows/workflow-lint.yml @@ -0,0 +1,36 @@ +name: Lint GitHub Actions workflow files + +on: + push: + branches: + - trunk + paths: + # Only run when changes are made to workflow files. + - '.github/workflows/**' + pull_request: + branches: + - trunk + paths: + # Only run when changes are made to workflow files. + - '.github/workflows/**' + workflow_dispatch: + +# Cancels all previous workflow runs for pull requests that have not completed. +concurrency: + # The concurrency group contains the workflow name and the branch name for pull requests + # or the commit hash for any other events. + 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: + lint: + name: Lint GitHub Action files + permissions: + security-events: write + actions: read + contents: read + uses: ./.github/workflows/reusable-workflow-lint.yml