mirror of
https://github.com/WordPress/create-block-theme.git
synced 2026-07-27 21:48:03 +08:00
* Add can_modify_theme() permission helper with DISALLOW_FILE_* respect
* Wire 9 mutating REST routes to can_modify_theme()
* Add multisite permission tests (skip when not in multisite env)
* Keep DISALLOW_FILE_* authoritative over the cbt_file_mods_allowed filter
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Assert /font-families returns 200 SUCCESS, not just not-403
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Avoid constructor side effects in invoke_private test helper
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Grant super-admin on multisite to isolate file-mod hardening assertion
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Update docblock
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Restore docblock close marker dropped by Copilot suggestion
* Delegate file-mod check to WP Core's wp_is_file_mod_allowed
scruffian flagged that the previous implementation bypassed WordPress
Core's canonical `file_mod_allowed` filter — the mechanism hosts and
security plugins use to disable file modifications globally.
Now delegates the DISALLOW_FILE_MODS / file_mod_allowed branch to
wp_is_file_mod_allowed( 'create_block_theme_modify_theme' ). The
explicit DISALLOW_FILE_EDIT check is kept on top because Core's
helper does NOT cover that constant (it's specifically for the theme
file editor UI).
The cbt_file_mods_allowed filter remains as a test seam — it can only
further restrict, never re-enable, the policy decided by core.
* Add regression test for cbt filter not overriding core file_mod_allowed
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Use edit_themes + wp_is_file_mod_allowed for permission check
Refactors can_modify_theme() to compose two WordPress Core primitives
instead of reimplementing the same checks:
current_user_can( 'edit_themes' )
&& wp_is_file_mod_allowed( 'create_block_theme_modify_theme' )
The edit_themes capability already encodes the matrix this plugin
needs: held by Administrators on single-site, super-admins on multisite
(NOT sub-site admins), and automatically denied by Core when
DISALLOW_FILE_EDIT is defined. wp_is_file_mod_allowed handles
DISALLOW_FILE_MODS and the canonical file_mod_allowed filter.
That removes:
- the explicit is_multisite() / is_super_admin() branch
- the explicit DISALLOW_FILE_EDIT constant check
- the file_mods_allowed() helper
- the cbt_file_mods_allowed filter (was a test seam; tests now use
the canonical file_mod_allowed filter instead)
Functional matrix is unchanged.
* Document /reset-theme cap reuse for permission-surface consistency
* Hide UI when REST capability gate denies
Sub-site admins on multisite, DISALLOW_FILE_EDIT/DISALLOW_FILE_MODS
sites, and sites that deny file_mod_allowed for the
create_block_theme_modify_theme context now get 403s from every
mutating REST route — but the admin landing page and editor sidebar
were still registered behind edit_theme_options, so those users could
open the UI and click primary actions that the API rejects.
Make can_modify_theme() public static on CBT_Theme_API and gate
- the Appearance > Create Block Theme menu entry, and
- the site-editor plugin sidebar enqueue
on the same predicate, so the UI surface matches the REST surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add multisite specific test runs
* Activate a block theme in UI-gate tests
Without an active block theme, both create_admin_menu() and
create_block_theme_sidebar_enqueue() return early on the
wp_is_block_theme() check — so the prior negative-only assertions
would have passed even if the cap gate did nothing. Activate a blank
block theme via the plugin's /create-blank endpoint (mirroring the
helper used in test-theme-fonts.php), then assert both directions:
menu/script register with the gate open, and drop out once
file_mod_allowed denies. This proves the cap gate (not the block-theme
guard) is what hides the UI.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Don't invoke sidebar enqueue under gate-open in test
The sidebar enqueue includes build/plugin-sidebar.asset.php on the
gate-open path; the CI test job doesn't build the plugin before
running PHP tests, so the previous version of this test errored on
that include. The cap-gate behaviour we care about is the gate-denied
path — that short-circuits before the include.
Drop the gate-open enqueue call and replace it with direct asserts on
the two preconditions (wp_is_block_theme() is true, $pagenow is
site-editor.php). That still proves the cap gate (not one of the
earlier guards) is what dropped the script, without depending on
build artefacts that CI doesn't produce.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
163 lines
5.4 KiB
YAML
163 lines
5.4 KiB
YAML
name: Run checks
|
|
on:
|
|
pull_request:
|
|
push:
|
|
branches:
|
|
- trunk
|
|
jobs:
|
|
lint:
|
|
name: Lint
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v3
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@v3
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache: npm
|
|
|
|
- name: Install dependencies
|
|
uses: php-actions/composer@v6
|
|
with:
|
|
args: --ignore-platform-reqs
|
|
|
|
- name: Install Dependencies
|
|
run: npm i
|
|
|
|
- name: Run PHP Lint
|
|
run: npm run lint:php
|
|
|
|
- name: Run JS Lint
|
|
if: success() || failure()
|
|
run: npm run lint:js
|
|
|
|
- name: Run CSS Lint
|
|
if: success() || failure()
|
|
run: npm run lint:css
|
|
|
|
- name: Run Markdown Lint
|
|
if: success() || failure()
|
|
run: npm run lint:md-docs
|
|
|
|
- name: Run package.json Lint
|
|
if: success() || failure()
|
|
run: npm run lint:pkg-json
|
|
|
|
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 }}
|
|
|
|
steps:
|
|
- name: Get previous WordPress version
|
|
id: get-previous-wordpress-version
|
|
run: |
|
|
curl \
|
|
-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)"
|
|
# shellcheck disable=SC2034
|
|
IFS='.' read -r LATEST_WP_MAJOR LATEST_WP_MINOR LATEST_WP_PATCH <<< "${LATEST_WP_VERSION}"
|
|
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"
|
|
rm versions.json
|
|
|
|
tests:
|
|
name: PHP ${{ matrix.php }}${{ matrix.wordpress != '' && format( ' (WP {0})', matrix.wordpress ) || '' }}
|
|
needs: [compute-previous-wordpress-version]
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
php: ['7.4', '8.0', '8.1', '8.2', '8.3']
|
|
wordpress: ['', 'previous major version']
|
|
env:
|
|
WP_ENV_PHP_VERSION: ${{ matrix.php }}
|
|
WP_ENV_CORE: ${{ matrix.wordpress == '' && 'WordPress/WordPress' || format( 'https://wordpress.org/wordpress-{0}.zip', needs.compute-previous-wordpress-version.outputs.previous-wordpress-version ) }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v3
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@v3
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache: npm
|
|
|
|
- name: Install Composer
|
|
uses: php-actions/composer@v6
|
|
with:
|
|
args: --ignore-platform-reqs
|
|
|
|
- name: Install Node Dependencies
|
|
run: npm i
|
|
|
|
- name: Set up PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '${{ matrix.php }}'
|
|
ini-file: development
|
|
coverage: none
|
|
|
|
- name: Docker debug information
|
|
run: docker -v
|
|
|
|
- name: Start Docker environment
|
|
run: npm run wp-env start
|
|
|
|
- name: Docker container debug information
|
|
run: npm run wp-env run tests-cli wp core version
|
|
|
|
- name: Log running Docker containers
|
|
run: docker ps -a
|
|
|
|
- name: Run PHP tests
|
|
run: npm run test:unit:php:base
|
|
|
|
- name: Run API PHP tests in multisite
|
|
run: npm run test:unit:php:multisite-api
|
|
e2e:
|
|
name: E2E Tests
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v3
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@v3
|
|
with:
|
|
node-version-file: '.nvmrc'
|
|
cache: npm
|
|
|
|
- name: Install Node Dependencies
|
|
run: npm i
|
|
|
|
- name: Build JavaScript
|
|
run: npm run build
|
|
|
|
- name: Install Playwright browsers
|
|
run: npx playwright install --with-deps chromium
|
|
|
|
- name: Start wp-env
|
|
run: npm run test:unit:php:setup
|
|
|
|
- name: Run E2E tests
|
|
run: npm run test:e2e
|
|
|
|
- name: Upload test artifacts on failure
|
|
uses: actions/upload-artifact@v4
|
|
if: failure()
|
|
with:
|
|
name: playwright-artifacts
|
|
path: artifacts/
|
|
if-no-files-found: ignore
|