From 4194ea90de2e37d6d32cd4cb7bbc71eb4d4ad669 Mon Sep 17 00:00:00 2001 From: Rias Date: Wed, 20 May 2026 20:58:54 +0200 Subject: [PATCH] Harden GitHub actions with zizmor suggestions --- .github/workflows/ci.yml | 2 +- .github/workflows/create-release.yml | 47 +++++++++++++--- .github/workflows/facades.yml | 49 +++++++++++----- .github/workflows/laravel-ci.yml | 84 ++++++++++++++++------------ .github/workflows/monorepo-split.yml | 16 +++++- 5 files changed, 136 insertions(+), 62 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a52685df804..0b012179af0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ concurrency: jobs: ci: name: ci - uses: craftcms/.github/.github/workflows/ci.yml@v3 + uses: craftcms/.github/.github/workflows/ci.yml@v3 # zizmor: ignore[unpinned-uses] This reusable workflow is maintained by Craft CMS; use the version tag for shared workflow updates. with: php_version: '8.5' craft_version: '6' diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 8e33492e59b..414d2e8e444 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -6,16 +6,47 @@ on: types: - craftcms/new-release +permissions: {} + +concurrency: + group: create-release-${{ github.event.client_payload.tag }} + cancel-in-progress: false + jobs: build: + name: Create release runs-on: ubuntu-latest permissions: - contents: write + contents: write # Required to create GitHub releases. steps: - - uses: ncipollo/release-action@v1 - with: - body: ${{ github.event.client_payload.notes }} - makeLatest: ${{ github.event.client_payload.latest }} - name: ${{ github.event.client_payload.version }} - prerelease: ${{ github.event.client_payload.prerelease }} - tag: ${{ github.event.client_payload.tag }} + - name: Create release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_BODY: ${{ github.event.client_payload.notes }} + RELEASE_LATEST: ${{ github.event.client_payload.latest }} + RELEASE_NAME: ${{ github.event.client_payload.version }} + RELEASE_PRERELEASE: ${{ github.event.client_payload.prerelease }} + RELEASE_TAG: ${{ github.event.client_payload.tag }} + run: | + args=(release create "$RELEASE_TAG" --title "$RELEASE_NAME" --notes "$RELEASE_BODY") + + if [[ "$RELEASE_PRERELEASE" == "true" ]]; then + args+=(--prerelease) + fi + + case "$RELEASE_LATEST" in + true) + args+=(--latest) + ;; + false) + args+=(--latest=false) + ;; + legacy|"") + ;; + *) + echo "Unsupported latest value: $RELEASE_LATEST" >&2 + exit 1 + ;; + esac + + gh "${args[@]}" diff --git a/.github/workflows/facades.yml b/.github/workflows/facades.yml index 85d88563ff6..7febf25c237 100644 --- a/.github/workflows/facades.yml +++ b/.github/workflows/facades.yml @@ -9,11 +9,17 @@ on: workflow_dispatch: permissions: - contents: write + contents: read + +concurrency: + group: facades-${{ github.ref }} + cancel-in-progress: true jobs: update: runs-on: ubuntu-24.04 + permissions: + contents: write # Required to push generated facade docblock commits. strategy: fail-fast: true @@ -22,10 +28,12 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2 with: php-version: 8.5 extensions: :php-psr @@ -44,13 +52,9 @@ jobs: } - name: Install dependencies - uses: nick-fields/retry@v3 - with: - timeout_minutes: 5 - max_attempts: 5 - command: | - composer config repositories.facade-documenter vcs git@github.com:laravel/facade-documenter.git - composer require --dev laravel/facade-documenter:dev-main --prefer-stable --prefer-dist --no-interaction --no-progress -W + run: | + composer config repositories.facade-documenter vcs git@github.com:laravel/facade-documenter.git + composer require --dev laravel/facade-documenter:dev-main --prefer-stable --prefer-dist --no-interaction --no-progress -W - name: Update facade docblocks run: | @@ -64,7 +68,24 @@ jobs: php -f vendor/bin/facade.php -- "${facade_classes[@]}" - name: Commit facade docblocks - uses: stefanzweifel/git-auto-commit-action@v7 - with: - commit_message: Update facade docblocks - file_pattern: src/ + env: + BRANCH: ${{ github.ref_name }} + GH_TOKEN: ${{ github.token }} + REF_TYPE: ${{ github.ref_type }} + run: | + if [[ "$REF_TYPE" != "branch" ]]; then + echo "Skipping commit on non-branch ref: $REF_TYPE" + exit 0 + fi + + if [[ -z "$(git status --porcelain -- src/)" ]]; then + echo "No facade docblock changes to commit." + exit 0 + fi + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add src/ + git commit -m "Update facade docblocks" + gh auth setup-git + git push origin "HEAD:${BRANCH}" diff --git a/.github/workflows/laravel-ci.yml b/.github/workflows/laravel-ci.yml index b79908c5471..5aa4819635d 100644 --- a/.github/workflows/laravel-ci.yml +++ b/.github/workflows/laravel-ci.yml @@ -7,6 +7,9 @@ on: - 6.x pull_request: +permissions: + contents: read + concurrency: group: laravel-ci-${{ github.ref }} cancel-in-progress: true @@ -19,12 +22,13 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ github.head_ref }} + persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2 with: php-version: '8.5' extensions: json, dom, curl, libxml, mbstring @@ -41,12 +45,13 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ github.head_ref }} + persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2 with: php-version: '8.5' extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo @@ -67,10 +72,10 @@ jobs: run: composer config version "6.x-dev" - name: Install dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@a8d0d959dab41457692a5e2041bd9b757a119e3f # v3 - name: Rector Cache - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: /tmp/rector key: ${{ runner.os }}-rector-${{ github.run_id }} @@ -86,10 +91,12 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc # v2 with: php-version: '8.5' extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo @@ -100,10 +107,10 @@ jobs: run: composer config version "6.x-dev" - name: Install composer dependencies - uses: ramsey/composer-install@v3 + uses: ramsey/composer-install@a8d0d959dab41457692a5e2041bd9b757a119e3f # v3 - name: PHPStan Cache - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: /tmp/phpstan key: ${{ runner.os }}-phpstan-${{ github.run_id }} @@ -124,7 +131,9 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Run tests uses: ./.github/actions/run-tests @@ -142,7 +151,9 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Run tests uses: ./.github/actions/run-tests @@ -164,40 +175,39 @@ jobs: php: [8.5] db: [mysql, pgsql, sqlite] exclude: - # Service containers (mysql/pgsql) are only supported on Linux runners. + # Preinstalled MySQL/PostgreSQL services are only available on Ubuntu runners. - os: windows-latest db: mysql - os: windows-latest db: pgsql - services: - pgsql: - image: ${{ (matrix.os == 'ubuntu-latest' && matrix.db == 'pgsql') && 'postgres:latest' || '' }} - env: - POSTGRES_USER: root - POSTGRES_PASSWORD: mysecretpassword - POSTGRES_DB: craft_test - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3 - mysql: - image: ${{ (matrix.os == 'ubuntu-latest' && matrix.db == 'mysql') && 'mysql:8.0' || '' }} - env: - MYSQL_ROOT_PASSWORD: mysecretpassword - MYSQL_DATABASE: craft_test - MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password - options: --health-cmd="mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 5 - ports: - - 3306:3306 steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: Start MySQL + if: matrix.os == 'ubuntu-latest' && matrix.db == 'mysql' + run: | + sudo systemctl start mysql.service + mysql --host=127.0.0.1 --user=root --password=root --execute="CREATE DATABASE IF NOT EXISTS craft_test" + + - name: Start PostgreSQL + if: matrix.os == 'ubuntu-latest' && matrix.db == 'pgsql' + run: | + sudo systemctl start postgresql.service + sudo -u postgres createuser --login --superuser root + sudo -u postgres psql -v ON_ERROR_STOP=1 --command="ALTER ROLE root WITH PASSWORD 'root'" + sudo -u postgres createdb --owner=root craft_test - name: Copy tests .env shell: bash + env: + DB: ${{ matrix.db }} run: | - cp ./tests/.env.example.${{ matrix.db }} ./tests/.env - sed -i 's/DB_PASSWORD=/DB_PASSWORD=mysecretpassword/' tests/.env + cp "./tests/.env.example.${DB}" ./tests/.env + sed -i 's/DB_PASSWORD=/DB_PASSWORD=root/' tests/.env touch database/craft_tests.sqlite - name: Run tests @@ -216,7 +226,9 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false - name: Run tests uses: ./.github/actions/run-tests diff --git a/.github/workflows/monorepo-split.yml b/.github/workflows/monorepo-split.yml index d201bb53a02..70487ca5377 100644 --- a/.github/workflows/monorepo-split.yml +++ b/.github/workflows/monorepo-split.yml @@ -9,16 +9,26 @@ on: - feature/split-packages tags: '*' +permissions: + contents: read + +concurrency: + group: monorepo-split-${{ github.ref }} + cancel-in-progress: true + jobs: split-monorepo: + name: Split monorepo runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + with: + persist-credentials: false # No tag - name: Monorepo Split if: "!startsWith(github.ref, 'refs/tags/')" - uses: danharrin/monorepo-split-github-action@v2.3.0 + uses: danharrin/monorepo-split-github-action@ac9845270ef47266435b4f124b133a323619e738 # v2.3.0 env: GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} with: @@ -32,7 +42,7 @@ jobs: # With Tag - name: Monorepo Split if: "startsWith(github.ref, 'refs/tags/')" - uses: danharrin/monorepo-split-github-action@v2.3.0 + uses: danharrin/monorepo-split-github-action@ac9845270ef47266435b4f124b133a323619e738 # v2.3.0 env: GITHUB_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} with: