From 14b4e4a376feabc363d69d6eb7731119e10e9b7e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 15 Apr 2026 23:40:31 +0000 Subject: [PATCH 1/5] ci: harden CI per Astral's open-source security recommendations Adopts the supply-chain practices described in Astral's "Open source security at Astral" post (https://astral.sh/blog/open-source-security-at-astral) and applies them to the FrankenPHP CI: - Add a zizmor workflow that audits every PR/push touching .github (and weekly on a schedule) as a hard gate. zizmor is installed via pipx so the security workflow itself has minimal supply chain. - Tighten every workflow to start with `permissions: {}` and grant the minimum permissions per job, so newly added jobs inherit nothing. - Track Docker base images with Dependabot so security patches in the underlying images surface as reviewable PRs. - Document the hardened posture (zizmor gate, least-privilege perms, environment-scoped secrets, build provenance, no pull_request_target) in SECURITY.md. - Document hash-pinning as the next ratchet in zizmor.yaml; the policy stays at `ref-pin` for now to avoid breaking existing tag pins, with a clear path to switch to `hash-pin` once Dependabot starts updating by SHA. https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T --- .github/dependabot.yaml | 18 +++++++ .github/workflows/docker.yaml | 9 +++- .github/workflows/lint.yaml | 9 ++-- .github/workflows/sanitizers.yaml | 5 +- .github/workflows/static.yaml | 7 ++- .github/workflows/tests.yaml | 9 +++- .github/workflows/translate.yaml | 7 +-- .github/workflows/windows.yaml | 3 +- .github/workflows/wrap-issue-details.yaml | 3 +- .github/workflows/zizmor.yaml | 60 +++++++++++++++++++++++ SECURITY.md | 31 ++++++++++++ zizmor.yaml | 10 ++++ 12 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/zizmor.yaml diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 28faaabf1c..2766464549 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -37,3 +37,21 @@ updates: - "*" cooldown: default-days: 7 + # Docker base images. Astral recommends keeping the supply chain + # under continuous review; Dependabot opens a PR whenever a new base + # image becomes available so we never silently fall behind security + # patches. + - package-ecosystem: docker + directories: + - / + - /caddy + schedule: + interval: weekly + commit-message: + prefix: chore(docker) + groups: + docker: + patterns: + - "*" + cooldown: + default-days: 7 diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index c1c29bbfc3..2d52b34934 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -30,13 +30,14 @@ on: type: string schedule: - cron: "0 4 * * *" -permissions: - contents: read +permissions: {} env: IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }} jobs: prepare: runs-on: ubuntu-24.04 + permissions: + contents: read outputs: # Push if it's a scheduled job, a tag, or if we're committing to the main branch push: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false }} @@ -82,6 +83,8 @@ jobs: build: environment: dockerhub runs-on: ${{ startsWith(matrix.platform, 'linux/arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }} + permissions: + contents: read needs: - prepare if: ${{ !fromJson(needs.prepare.outputs.skip) }} @@ -207,6 +210,8 @@ jobs: push: environment: dockerhub runs-on: ubuntu-24.04 + permissions: + contents: read needs: - prepare - build diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 7a4f83a0c9..88989676cc 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -10,14 +10,15 @@ on: push: branches: - main -permissions: - contents: read - packages: read - statuses: write +permissions: {} jobs: build: name: Lint Code Base runs-on: ubuntu-latest + permissions: + contents: read + packages: read + statuses: write steps: - name: Checkout Code uses: actions/checkout@v6 diff --git a/.github/workflows/sanitizers.yaml b/.github/workflows/sanitizers.yaml index 15fe013d5b..ba4f8c9080 100644 --- a/.github/workflows/sanitizers.yaml +++ b/.github/workflows/sanitizers.yaml @@ -14,8 +14,7 @@ on: - main paths-ignore: - "docs/**" -permissions: - contents: read +permissions: {} env: GOTOOLCHAIN: local GOTESTSUM_FORMAT: pkgname-and-test-fails @@ -24,6 +23,8 @@ jobs: sanitizers: name: ${{ matrix.sanitizer }} runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false matrix: diff --git a/.github/workflows/static.yaml b/.github/workflows/static.yaml index 165c48bcb2..5724b1ce11 100644 --- a/.github/workflows/static.yaml +++ b/.github/workflows/static.yaml @@ -32,8 +32,7 @@ on: schedule: - cron: "0 0 * * *" -permissions: - contents: read +permissions: {} env: IMAGE_NAME: ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/')) && 'dunglas/frankenphp' || 'dunglas/frankenphp-dev' }} @@ -43,6 +42,8 @@ env: jobs: prepare: runs-on: ubuntu-24.04 + permissions: + contents: read outputs: push: ${{ toJson((steps.check.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || startsWith(github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name != 'pull_request')) && true || false) }} platforms: ${{ steps.matrix.outputs.platforms }} @@ -381,6 +382,8 @@ jobs: push: environment: dockerhub runs-on: ubuntu-24.04 + permissions: + contents: read needs: - prepare - build-linux-musl diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 396d9ccf77..9e4c8e1905 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -14,8 +14,7 @@ on: - main paths-ignore: - "docs/**" -permissions: - contents: read +permissions: {} env: GOTOOLCHAIN: local GOEXPERIMENT: cgocheck2 @@ -25,6 +24,8 @@ jobs: name: Tests (Linux, PHP ${{ matrix.php-versions }}) runs-on: ubuntu-latest continue-on-error: false + permissions: + contents: read strategy: fail-fast: false matrix: @@ -98,6 +99,8 @@ jobs: integration-tests: name: Integration Tests (Linux, PHP ${{ matrix.php-versions }}) runs-on: ubuntu-latest + permissions: + contents: read strategy: fail-fast: false matrix: @@ -145,6 +148,8 @@ jobs: tests-mac: name: Tests (macOS, PHP 8.5) runs-on: macos-latest + permissions: + contents: read env: HOMEBREW_NO_AUTO_UPDATE: 1 GOFLAGS: "-tags=nowatcher,nobadger,nomysql,nopgx" diff --git a/.github/workflows/translate.yaml b/.github/workflows/translate.yaml index c8bf52b099..e421d8695e 100644 --- a/.github/workflows/translate.yaml +++ b/.github/workflows/translate.yaml @@ -8,14 +8,15 @@ on: - main paths: - "docs/*" -permissions: - contents: write - pull-requests: write +permissions: {} jobs: build: environment: translate name: Translate Docs runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write steps: - name: Checkout Code uses: actions/checkout@v6 diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index 8da5547899..c2817329a3 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -28,8 +28,7 @@ on: schedule: - cron: "0 8 * * *" -permissions: - contents: read +permissions: {} env: GOTOOLCHAIN: local diff --git a/.github/workflows/wrap-issue-details.yaml b/.github/workflows/wrap-issue-details.yaml index fe240552af..81f84d1630 100644 --- a/.github/workflows/wrap-issue-details.yaml +++ b/.github/workflows/wrap-issue-details.yaml @@ -3,8 +3,7 @@ on: issues: types: [opened, edited] -permissions: - contents: read +permissions: {} jobs: wrap_content: diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml new file mode 100644 index 0000000000..9a7e52c5c9 --- /dev/null +++ b/.github/workflows/zizmor.yaml @@ -0,0 +1,60 @@ +--- +# Static analysis of GitHub Actions workflows. +# +# Inspired by Astral's open-source security guidance: +# https://astral.sh/blog/open-source-security-at-astral +# +# zizmor catches misuses such as template injection, credential leaks, +# excessive permissions, dangerous triggers and impostor commits. It is +# a hard CI gate: a failed audit blocks the pull request. +name: GitHub Actions Security Audit +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} +on: + pull_request: + branches: + - main + paths: + - .github/** + - zizmor.yaml + push: + branches: + - main + paths: + - .github/** + - zizmor.yaml + schedule: + # Re-audit weekly so newly published advisories surface even if + # no workflow file has changed. + - cron: "0 6 * * 1" +permissions: {} +jobs: + zizmor: + name: zizmor + runs-on: ubuntu-latest + permissions: + contents: read + # Required so zizmor can upload SARIF results to GitHub Code + # Scanning. Drop this permission if Code Scanning is unavailable. + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + persist-credentials: false + # zizmor is installed via pipx (preinstalled on ubuntu-latest) + # rather than a third-party action so the security workflow has + # the smallest possible supply chain. + - name: Install zizmor + run: pipx install zizmor + - name: Run zizmor + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: zizmor --format=sarif --min-severity=low . > zizmor.sarif + - name: Upload SARIF file + if: ${{ !cancelled() }} + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: zizmor.sarif + category: zizmor diff --git a/SECURITY.md b/SECURITY.md index ba241ac655..90e0c3f00c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,3 +16,34 @@ Please write a detailed vulnerability report and send it [through GitHub](https: Only vulnerabilities directly affecting FrankenPHP should be reported to this project. Flaws affecting components used by FrankenPHP (PHP, Caddy, Go...) or using FrankenPHP (Laravel Octane, PHP Runtime...) should be reported to the relevant projects. + +## Supply-chain hardening + +FrankenPHP follows the open-source security practices documented in +[Astral's "Open source security at Astral" post](https://astral.sh/blog/open-source-security-at-astral): + +- **Workflow auditing.** Every push and pull request that touches CI + is audited by [zizmor](https://docs.zizmor.sh/) as a hard gate. The + `unpinned-uses` rule in `zizmor.yaml` requires, at a minimum, a tag + pin on every action. +- **Least-privilege permissions.** Every workflow starts with + `permissions: {}` and only broadens access on a per-job basis, so a + newly added job inherits no permissions by default. +- **Environment-scoped secrets.** Secrets that publish artifacts + (Docker Hub credentials, the website deploy token, the translation + API key) live in dedicated GitHub Environments (`dockerhub`, + `website`, `translate`) instead of repository-wide secrets, + limiting the blast radius of a compromised job. +- **Build provenance.** Release binaries are attested with + [`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance) + so downstream consumers can verify they were produced by this + repository's CI. +- **Continuous dependency updates.** Dependabot tracks Go modules, + GitHub Actions and Docker base images; new versions land through + reviewable pull requests rather than implicit `latest` upgrades. +- **No `pull_request_target`.** Workflows never use the + `pull_request_target` trigger, which would expose write tokens to + fork pull requests. +- **Checkout without persisted credentials.** All `actions/checkout` + steps set `persist-credentials: false` unless they specifically + need to push back to the repository. diff --git a/zizmor.yaml b/zizmor.yaml index bbb03663b7..33c9884ffd 100644 --- a/zizmor.yaml +++ b/zizmor.yaml @@ -1,6 +1,16 @@ --- +# zizmor static-analysis configuration. +# +# See https://docs.zizmor.sh/configuration/ for the full reference. +# +# Inspired by Astral's open-source security guidance: +# https://astral.sh/blog/open-source-security-at-astral rules: unpinned-uses: config: policies: + # Every action must be pinned to at least a tag (`@v6`). + # Hash-pinning to a commit SHA is the long-term goal recommended + # by Astral; once the migration is complete, switch this policy + # to `hash-pin` so that mutable tags can no longer reach CI. "*": ref-pin From f1b7bf97d07246a37f6eae304f18896fe3a23b75 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Apr 2026 05:54:42 +0000 Subject: [PATCH 2/5] ci: remove standalone zizmor workflow, fix SECURITY.md lint zizmor already runs as GITHUB_ACTIONS_ZIZMOR inside Super Linter, so the dedicated workflow was redundant. Also simplify the SECURITY.md prose to pass the NATURAL_LANGUAGE linter. https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T --- .github/workflows/zizmor.yaml | 60 ----------------------------------- SECURITY.md | 51 ++++++++++++++--------------- 2 files changed, 23 insertions(+), 88 deletions(-) delete mode 100644 .github/workflows/zizmor.yaml diff --git a/.github/workflows/zizmor.yaml b/.github/workflows/zizmor.yaml deleted file mode 100644 index 9a7e52c5c9..0000000000 --- a/.github/workflows/zizmor.yaml +++ /dev/null @@ -1,60 +0,0 @@ ---- -# Static analysis of GitHub Actions workflows. -# -# Inspired by Astral's open-source security guidance: -# https://astral.sh/blog/open-source-security-at-astral -# -# zizmor catches misuses such as template injection, credential leaks, -# excessive permissions, dangerous triggers and impostor commits. It is -# a hard CI gate: a failed audit blocks the pull request. -name: GitHub Actions Security Audit -concurrency: - cancel-in-progress: true - group: ${{ github.workflow }}-${{ github.ref }} -on: - pull_request: - branches: - - main - paths: - - .github/** - - zizmor.yaml - push: - branches: - - main - paths: - - .github/** - - zizmor.yaml - schedule: - # Re-audit weekly so newly published advisories surface even if - # no workflow file has changed. - - cron: "0 6 * * 1" -permissions: {} -jobs: - zizmor: - name: zizmor - runs-on: ubuntu-latest - permissions: - contents: read - # Required so zizmor can upload SARIF results to GitHub Code - # Scanning. Drop this permission if Code Scanning is unavailable. - security-events: write - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - persist-credentials: false - # zizmor is installed via pipx (preinstalled on ubuntu-latest) - # rather than a third-party action so the security workflow has - # the smallest possible supply chain. - - name: Install zizmor - run: pipx install zizmor - - name: Run zizmor - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: zizmor --format=sarif --min-severity=low . > zizmor.sarif - - name: Upload SARIF file - if: ${{ !cancelled() }} - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: zizmor.sarif - category: zizmor diff --git a/SECURITY.md b/SECURITY.md index 90e0c3f00c..a64b3bcc3c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -19,31 +19,26 @@ Flaws affecting components used by FrankenPHP (PHP, Caddy, Go...) or using Frank ## Supply-chain hardening -FrankenPHP follows the open-source security practices documented in -[Astral's "Open source security at Astral" post](https://astral.sh/blog/open-source-security-at-astral): - -- **Workflow auditing.** Every push and pull request that touches CI - is audited by [zizmor](https://docs.zizmor.sh/) as a hard gate. The - `unpinned-uses` rule in `zizmor.yaml` requires, at a minimum, a tag - pin on every action. -- **Least-privilege permissions.** Every workflow starts with - `permissions: {}` and only broadens access on a per-job basis, so a - newly added job inherits no permissions by default. -- **Environment-scoped secrets.** Secrets that publish artifacts - (Docker Hub credentials, the website deploy token, the translation - API key) live in dedicated GitHub Environments (`dockerhub`, - `website`, `translate`) instead of repository-wide secrets, - limiting the blast radius of a compromised job. -- **Build provenance.** Release binaries are attested with - [`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance) - so downstream consumers can verify they were produced by this - repository's CI. -- **Continuous dependency updates.** Dependabot tracks Go modules, - GitHub Actions and Docker base images; new versions land through - reviewable pull requests rather than implicit `latest` upgrades. -- **No `pull_request_target`.** Workflows never use the - `pull_request_target` trigger, which would expose write tokens to - fork pull requests. -- **Checkout without persisted credentials.** All `actions/checkout` - steps set `persist-credentials: false` unless they specifically - need to push back to the repository. +FrankenPHP follows the open-source security practices from +[Astral's security guide](https://astral.sh/blog/open-source-security-at-astral): + +- **Workflow auditing** -- + [Super Linter](https://github.com/super-linter/super-linter) runs + [zizmor](https://docs.zizmor.sh/) on every pull request. + The `unpinned-uses` rule in `zizmor.yaml` requires a tag pin on every action. +- **Least-privilege permissions** -- + Every workflow starts with `permissions: {}` and only grants access per job. +- **Environment-scoped secrets** -- + Secrets for publishing (Docker Hub, website deploy, translation API) + live in dedicated GitHub Environments (`dockerhub`, `website`, `translate`). +- **Build provenance** -- + Release binaries carry + [`attest-build-provenance`](https://github.com/actions/attest-build-provenance) + attestations. +- **Dependency updates** -- + Dependabot tracks Go modules, GitHub Actions, and Docker base images. +- **Safe triggers** -- + Workflows never use `pull_request_target`. +- **No persisted credentials** -- + All `actions/checkout` steps set `persist-credentials: false` + unless the job needs to push. From 340f3dba8416968be271f0472deaba60310622eb Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Apr 2026 06:03:46 +0000 Subject: [PATCH 3/5] ci: revert SECURITY.md, docker dependabot, and zizmor comments - Revert SECURITY.md to original (no new sections) - Remove docker package-ecosystem from Dependabot (nightly scheduled workflow already updates base images) - Remove added comments and Astral references from zizmor.yaml https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T --- .github/dependabot.yaml | 18 ------------------ SECURITY.md | 26 -------------------------- zizmor.yaml | 10 ---------- 3 files changed, 54 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 2766464549..28faaabf1c 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -37,21 +37,3 @@ updates: - "*" cooldown: default-days: 7 - # Docker base images. Astral recommends keeping the supply chain - # under continuous review; Dependabot opens a PR whenever a new base - # image becomes available so we never silently fall behind security - # patches. - - package-ecosystem: docker - directories: - - / - - /caddy - schedule: - interval: weekly - commit-message: - prefix: chore(docker) - groups: - docker: - patterns: - - "*" - cooldown: - default-days: 7 diff --git a/SECURITY.md b/SECURITY.md index a64b3bcc3c..ba241ac655 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,29 +16,3 @@ Please write a detailed vulnerability report and send it [through GitHub](https: Only vulnerabilities directly affecting FrankenPHP should be reported to this project. Flaws affecting components used by FrankenPHP (PHP, Caddy, Go...) or using FrankenPHP (Laravel Octane, PHP Runtime...) should be reported to the relevant projects. - -## Supply-chain hardening - -FrankenPHP follows the open-source security practices from -[Astral's security guide](https://astral.sh/blog/open-source-security-at-astral): - -- **Workflow auditing** -- - [Super Linter](https://github.com/super-linter/super-linter) runs - [zizmor](https://docs.zizmor.sh/) on every pull request. - The `unpinned-uses` rule in `zizmor.yaml` requires a tag pin on every action. -- **Least-privilege permissions** -- - Every workflow starts with `permissions: {}` and only grants access per job. -- **Environment-scoped secrets** -- - Secrets for publishing (Docker Hub, website deploy, translation API) - live in dedicated GitHub Environments (`dockerhub`, `website`, `translate`). -- **Build provenance** -- - Release binaries carry - [`attest-build-provenance`](https://github.com/actions/attest-build-provenance) - attestations. -- **Dependency updates** -- - Dependabot tracks Go modules, GitHub Actions, and Docker base images. -- **Safe triggers** -- - Workflows never use `pull_request_target`. -- **No persisted credentials** -- - All `actions/checkout` steps set `persist-credentials: false` - unless the job needs to push. diff --git a/zizmor.yaml b/zizmor.yaml index 33c9884ffd..bbb03663b7 100644 --- a/zizmor.yaml +++ b/zizmor.yaml @@ -1,16 +1,6 @@ --- -# zizmor static-analysis configuration. -# -# See https://docs.zizmor.sh/configuration/ for the full reference. -# -# Inspired by Astral's open-source security guidance: -# https://astral.sh/blog/open-source-security-at-astral rules: unpinned-uses: config: policies: - # Every action must be pinned to at least a tag (`@v6`). - # Hash-pinning to a commit SHA is the long-term goal recommended - # by Astral; once the migration is complete, switch this policy - # to `hash-pin` so that mutable tags can no longer reach CI. "*": ref-pin From 5c34fea61128ac8d0c433136dd2728bf7a580c66 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 16 Apr 2026 06:06:25 +0000 Subject: [PATCH 4/5] ci: hash-pin all GitHub Actions and auto-merge Dependabot updates Pin every external action to its commit SHA so mutable tags can no longer alter what runs in CI. The zizmor policy is switched from ref-pin to hash-pin to enforce this going forward. Dependabot already tracks the github-actions ecosystem weekly and will open PRs to bump the SHA pins. A new auto-merge workflow approves and squash-merges minor/patch GitHub Actions updates from Dependabot automatically, keeping pins current without manual churn. https://claude.ai/code/session_01YEC8c9bU4Mory8FFoiAS5T --- .github/actions/watcher/action.yaml | 2 +- .github/workflows/dependabot.yaml | 25 ++++++++++++ .github/workflows/docker.yaml | 22 +++++----- .github/workflows/lint.yaml | 4 +- .github/workflows/sanitizers.yaml | 6 +-- .github/workflows/static.yaml | 50 +++++++++++------------ .github/workflows/tests.yaml | 20 ++++----- .github/workflows/translate.yaml | 6 +-- .github/workflows/windows.yaml | 6 +-- .github/workflows/wrap-issue-details.yaml | 2 +- zizmor.yaml | 2 +- 11 files changed, 85 insertions(+), 60 deletions(-) create mode 100644 .github/workflows/dependabot.yaml diff --git a/.github/actions/watcher/action.yaml b/.github/actions/watcher/action.yaml index 2025f65c21..55749a5f82 100644 --- a/.github/actions/watcher/action.yaml +++ b/.github/actions/watcher/action.yaml @@ -11,7 +11,7 @@ runs: GH_TOKEN: ${{ github.token }} - name: Cache e-dant/watcher id: cache-watcher - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: watcher/target key: watcher-${{ runner.os }}-${{ runner.arch }}-${{ steps.determine-watcher-version.outputs.version }}-${{ env.CC && env.CC || 'gcc' }} diff --git a/.github/workflows/dependabot.yaml b/.github/workflows/dependabot.yaml new file mode 100644 index 0000000000..6dfb1bfb85 --- /dev/null +++ b/.github/workflows/dependabot.yaml @@ -0,0 +1,25 @@ +--- +name: Dependabot Auto-Merge +on: pull_request +permissions: {} +jobs: + auto-merge: + if: github.actor == 'dependabot[bot]' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@21025c705c08248db411dc16f3619e6b5f9ea21a # v2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + - name: Auto-merge minor and patch GitHub Actions updates + if: steps.metadata.outputs.package-ecosystem == 'github_actions' && steps.metadata.outputs.update-type != 'version-update:semver-major' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + gh pr review --approve "${PR_URL}" + gh pr merge --auto --squash "${PR_URL}" diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index 2d52b34934..f8d7f8bc99 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -53,12 +53,12 @@ jobs: ref: ${{ steps.check.outputs.ref || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }} base_fingerprint: ${{ steps.check.outputs.base_fingerprint }} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 - name: Check PHP versions and base image fingerprint id: check env: @@ -121,23 +121,23 @@ jobs: run: echo "sanitized_platform=${PLATFORM//\//-}" >> "${GITHUB_OUTPUT}" env: PLATFORM: ${{ matrix.platform }} - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.prepare.outputs.ref }} persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 with: platforms: ${{ matrix.platform }} - name: Login to DockerHub - uses: docker/login-action@v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository with: username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build id: build - uses: docker/bake-action@v7 + uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7 with: pull: true load: ${{ !fromJson(needs.prepare.outputs.push) }} @@ -178,7 +178,7 @@ jobs: VARIANT: ${{ matrix.variant }} - name: Upload builder metadata if: fromJson(needs.prepare.outputs.push) - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: metadata-builder-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }} path: /tmp/metadata/builder/* @@ -186,7 +186,7 @@ jobs: retention-days: 1 - name: Upload runner metadata if: fromJson(needs.prepare.outputs.push) - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: metadata-runner-${{ matrix.variant }}-${{ steps.prepare.outputs.sanitized_platform }} path: /tmp/metadata/runner/* @@ -223,15 +223,15 @@ jobs: target: ["builder", "runner"] steps: - name: Download metadata - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: metadata-${{ matrix.target }}-${{ matrix.variant }}-* path: /tmp/metadata merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 - name: Login to DockerHub - uses: docker/login-action@v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository with: username: ${{ vars.DOCKERHUB_USERNAME }} diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 88989676cc..d491107851 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -21,12 +21,12 @@ jobs: statuses: write steps: - name: Checkout Code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 persist-credentials: false - name: Lint Code Base - uses: super-linter/super-linter/slim@v8 + uses: super-linter/super-linter/slim@d24d9629088c26de5cc684fbe17d1843469c37e0 # v8 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LINTER_RULES_PATH: / diff --git a/.github/workflows/sanitizers.yaml b/.github/workflows/sanitizers.yaml index ba4f8c9080..7eab4decdd 100644 --- a/.github/workflows/sanitizers.yaml +++ b/.github/workflows/sanitizers.yaml @@ -42,10 +42,10 @@ jobs: steps: - name: Remove local PHP run: sudo apt-get remove --purge --autoremove 'php*' 'libmemcached*' - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version: "1.26" cache-dependency-path: | @@ -59,7 +59,7 @@ jobs: echo archive="$(jq -r '.[] .source[] | select(.filename |endswith(".xz")) | "https://www.php.net/distributions/" + .filename' version.json)" >> "$GITHUB_OUTPUT" - name: Cache PHP id: cache-php - uses: actions/cache@v5 + uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 with: path: php/target key: php-sanitizers-${{ matrix.sanitizer }}-${{ runner.arch }}-${{ steps.determine-php-version.outputs.version }} diff --git a/.github/workflows/static.yaml b/.github/workflows/static.yaml index 5724b1ce11..2defcb6ceb 100644 --- a/.github/workflows/static.yaml +++ b/.github/workflows/static.yaml @@ -64,12 +64,12 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REF: ${{ (github.ref_type == 'tag' && github.ref_name) || (github.event_name == 'workflow_dispatch' && inputs.version) || '' }} - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ steps.check.outputs.ref }} persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 - name: Create platforms matrix id: matrix run: | @@ -111,16 +111,16 @@ jobs: run: echo "sanitized_platform=${PLATFORM//\//-}" >> "${GITHUB_OUTPUT}" env: PLATFORM: ${{ matrix.platform }} - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.prepare.outputs.ref }} persist-credentials: false - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 with: platforms: ${{ matrix.platform }} - name: Login to DockerHub - uses: docker/login-action@v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository with: username: ${{ vars.DOCKERHUB_USERNAME }} @@ -140,7 +140,7 @@ jobs: REF: ${{ needs.prepare.outputs.ref }} - name: Build id: build - uses: docker/bake-action@v7 + uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7 with: pull: true load: ${{ !fromJson(needs.prepare.outputs.push) || matrix.debug || matrix.mimalloc }} @@ -172,7 +172,7 @@ jobs: METADATA: ${{ steps.build.outputs.metadata }} - name: Upload metadata if: fromJson(needs.prepare.outputs.push) && !matrix.debug && !matrix.mimalloc - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: metadata-static-builder-musl-${{ steps.prepare.outputs.sanitized_platform }} path: /tmp/metadata/* @@ -192,7 +192,7 @@ jobs: PLATFORM: ${{ matrix.platform }} - name: Upload artifact if: ${{ !fromJson(needs.prepare.outputs.push) }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }} path: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}${{ matrix.debug && '-debug' || '' }}${{ matrix.mimalloc && '-mimalloc' || '' }} @@ -204,7 +204,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REF: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }} - if: fromJson(needs.prepare.outputs.push) && (needs.prepare.outputs.ref || github.ref_type == 'tag') - uses: actions/attest-build-provenance@v4 + uses: actions/attest-build-provenance@b3e506e8c389afc651c5bacf2b8f2a1ea0557215 # v4 with: subject-path: ${{ github.workspace }}/frankenphp-linux-* - name: Run sanity checks @@ -267,7 +267,7 @@ jobs: run: echo "sanitized_platform=${PLATFORM//\//-}" >> "${GITHUB_OUTPUT}" env: PLATFORM: ${{ matrix.platform }} - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.prepare.outputs.ref }} persist-credentials: false @@ -285,18 +285,18 @@ jobs: env: REF: ${{ needs.prepare.outputs.ref }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 with: platforms: ${{ matrix.platform }} - name: Login to DockerHub - uses: docker/login-action@v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository with: username: ${{ vars.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build id: build - uses: docker/bake-action@v7 + uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7 with: pull: true load: ${{ !fromJson(needs.prepare.outputs.push) }} @@ -326,7 +326,7 @@ jobs: METADATA: ${{ steps.build.outputs.metadata }} - name: Upload metadata if: fromJson(needs.prepare.outputs.push) - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: metadata-static-builder-gnu-${{ steps.prepare.outputs.sanitized_platform }} path: /tmp/metadata-gnu/* @@ -352,7 +352,7 @@ jobs: PLATFORM: ${{ matrix.platform }} - name: Upload artifact if: ${{ !fromJson(needs.prepare.outputs.push) }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: frankenphp-linux-${{ matrix.platform == 'linux/amd64' && 'x86_64' || 'aarch64' }}-gnu-files path: gh-output/* @@ -363,7 +363,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REF: ${{ (github.ref_type == 'tag' && github.ref_name) || needs.prepare.outputs.ref }} - if: fromJson(needs.prepare.outputs.push) && (needs.prepare.outputs.ref || github.ref_type == 'tag') - uses: actions/attest-build-provenance@v4 + uses: actions/attest-build-provenance@b3e506e8c389afc651c5bacf2b8f2a1ea0557215 # v4 with: subject-path: ${{ github.workspace }}/gh-output/frankenphp-linux-*-gnu - name: Run sanity checks @@ -391,21 +391,21 @@ jobs: if: fromJson(needs.prepare.outputs.push) steps: - name: Download metadata - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: metadata-static-builder-musl-* path: /tmp/metadata merge-multiple: true - name: Download GNU metadata - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: pattern: metadata-static-builder-gnu-* path: /tmp/metadata-gnu merge-multiple: true - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 - name: Login to DockerHub - uses: docker/login-action@v4 + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository with: username: ${{ vars.DOCKERHUB_USERNAME }} @@ -454,11 +454,11 @@ jobs: env: HOMEBREW_NO_AUTO_UPDATE: 1 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ needs.prepare.outputs.ref }} persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: # zizmor: ignore[cache-poisoning] go-version: "1.26" cache-dependency-path: | @@ -486,17 +486,17 @@ jobs: NO_COMPRESS: ${{ github.event_name == 'pull_request' && '1' || '' }} - name: Upload logs if: ${{ failure() }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: path: dist/static-php-cli/log name: static-php-cli-log-${{ matrix.platform }}-${{ github.sha }} - if: needs.prepare.outputs.ref || github.ref_type == 'tag' - uses: actions/attest-build-provenance@v4 + uses: actions/attest-build-provenance@b3e506e8c389afc651c5bacf2b8f2a1ea0557215 # v4 with: subject-path: ${{ github.workspace }}/dist/frankenphp-mac-* - name: Upload artifact if: github.ref_type == 'branch' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: frankenphp-mac-${{ matrix.platform }} path: dist/frankenphp-mac-${{ matrix.platform }} diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9e4c8e1905..276325fdaf 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -39,16 +39,16 @@ jobs: LIBRARY_PATH: ${{ github.workspace }}/watcher/target/lib GOFLAGS: "-tags=nobadger,nomysql,nopgx" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version: "1.26" cache-dependency-path: | go.sum caddy/go.sum - - uses: shivammathur/setup-php@v2 + - uses: shivammathur/setup-php@728c6c6b8cf02c2e48117716a91ee48313958a19 # v2 with: php-version: ${{ matrix.php-versions }} ini-file: development @@ -85,7 +85,7 @@ jobs: - name: Run integrations tests run: ./reload_test.sh - name: Lint Go code - uses: golangci/golangci-lint-action@v9 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 if: matrix.php-versions == '8.5' with: version: latest @@ -108,16 +108,16 @@ jobs: env: XCADDY_GO_BUILD_FLAGS: "-tags=nobadger,nomysql,nopgx" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version: "1.26" cache-dependency-path: | go.sum caddy/go.sum - - uses: shivammathur/setup-php@v2 + - uses: shivammathur/setup-php@728c6c6b8cf02c2e48117716a91ee48313958a19 # v2 with: php-version: ${{ matrix.php-versions }} ini-file: development @@ -154,16 +154,16 @@ jobs: HOMEBREW_NO_AUTO_UPDATE: 1 GOFLAGS: "-tags=nowatcher,nobadger,nomysql,nopgx" steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: persist-credentials: false - - uses: actions/setup-go@v6 + - uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: go-version: "1.26" cache-dependency-path: | go.sum caddy/go.sum - - uses: shivammathur/setup-php@v2 + - uses: shivammathur/setup-php@728c6c6b8cf02c2e48117716a91ee48313958a19 # v2 with: php-version: 8.5 ini-file: development diff --git a/.github/workflows/translate.yaml b/.github/workflows/translate.yaml index e421d8695e..282b84f178 100644 --- a/.github/workflows/translate.yaml +++ b/.github/workflows/translate.yaml @@ -19,7 +19,7 @@ jobs: pull-requests: write steps: - name: Checkout Code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: fetch-depth: 0 # zizmor: ignore[artipacked] @@ -33,7 +33,7 @@ jobs: echo "files=$FILES" >> "$GITHUB_OUTPUT" - name: Set up PHP if: steps.md_files.outputs.found == 'true' - uses: shivammathur/setup-php@v2 + uses: shivammathur/setup-php@728c6c6b8cf02c2e48117716a91ee48313958a19 # v2 with: php-version: "8.5" - name: run translation script @@ -46,7 +46,7 @@ jobs: - name: Run Linter if: steps.md_files.outputs.found == 'true' continue-on-error: true - uses: super-linter/super-linter/slim@v8 + uses: super-linter/super-linter/slim@d24d9629088c26de5cc684fbe17d1843469c37e0 # v8 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LINTER_RULES_PATH: / diff --git a/.github/workflows/windows.yaml b/.github/workflows/windows.yaml index c2817329a3..1ddcd2f51d 100644 --- a/.github/workflows/windows.yaml +++ b/.github/workflows/windows.yaml @@ -62,7 +62,7 @@ jobs: git config --global core.eol lf - name: Checkout Code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ env.REF || '' }} path: frankenphp @@ -87,7 +87,7 @@ jobs: "FRANKENPHP_VERSION=$frankenphpVersion" >> $env:GITHUB_ENV - name: Setup Go - uses: actions/setup-go@v6 + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6 with: # zizmor: ignore[cache-poisoning] go-version: "1.26" cache-dependency-path: | @@ -207,7 +207,7 @@ jobs: - name: Upload Artifact if: ${{ !env.REF }} - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: ${{ env.DIR_NAME }} path: ${{ env.DIR_NAME }} diff --git a/.github/workflows/wrap-issue-details.yaml b/.github/workflows/wrap-issue-details.yaml index 81f84d1630..553d2e6eb4 100644 --- a/.github/workflows/wrap-issue-details.yaml +++ b/.github/workflows/wrap-issue-details.yaml @@ -11,7 +11,7 @@ jobs: permissions: issues: write steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 with: script: | const body = context.payload.issue.body; diff --git a/zizmor.yaml b/zizmor.yaml index bbb03663b7..1983671691 100644 --- a/zizmor.yaml +++ b/zizmor.yaml @@ -3,4 +3,4 @@ rules: unpinned-uses: config: policies: - "*": ref-pin + "*": hash-pin From 899cfb634cafac4743d46fcad0231fc4013beb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 16 Apr 2026 16:00:28 +0200 Subject: [PATCH 5/5] Delete zizmor.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Kévin Dunglas --- zizmor.yaml | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 zizmor.yaml diff --git a/zizmor.yaml b/zizmor.yaml deleted file mode 100644 index 1983671691..0000000000 --- a/zizmor.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -rules: - unpinned-uses: - config: - policies: - "*": hash-pin