From 81562736695c1e2200b1b78fbe9c57b47bd90dc9 Mon Sep 17 00:00:00 2001 From: James Titcumb Date: Wed, 27 Nov 2024 08:02:55 +0000 Subject: [PATCH 1/2] Use GH attestation and organise workflows better --- ...lease-unsigned-phar.yml => build-phar.yml} | 21 +++++- .github/workflows/continuous-integration.yml | 7 +- .github/workflows/docs.yml | 17 +++-- .github/workflows/release.yml | 66 ++++++------------- README.md | 2 +- docs/usage.md | 4 +- 6 files changed, 60 insertions(+), 57 deletions(-) rename .github/workflows/{release-unsigned-phar.yml => build-phar.yml} (57%) diff --git a/.github/workflows/release-unsigned-phar.yml b/.github/workflows/build-phar.yml similarity index 57% rename from .github/workflows/release-unsigned-phar.yml rename to .github/workflows/build-phar.yml index 959d52b..1a29eac 100644 --- a/.github/workflows/release-unsigned-phar.yml +++ b/.github/workflows/build-phar.yml @@ -1,4 +1,14 @@ -name: "Release unsigned PHAR" +# Invoking this pipeline requires additional permissions, so must be invoked +# in a way to pass those permissions on, e.g.: +# +# build-phar: +# permissions: +# contents: read +# id-token: write +# attestations: write +# uses: ./.github/workflows/build-phar.yml + +name: "Build the PIE PHAR" on: workflow_call: @@ -15,6 +25,11 @@ jobs: - ubuntu-latest php-versions: - '8.1' + permissions: + # id-token:write is required for build provenance attestation. + id-token: write + # attestations:write is required for build provenance attestation. + attestations: write steps: - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -32,6 +47,10 @@ jobs: run: box compile - name: Check the PHAR executes run: php pie.phar --version + - name: Generate build provenance attestation + uses: actions/attest-build-provenance@v1 + with: + subject-path: '${{ github.workspace }}/pie.phar' - uses: actions/upload-artifact@v4 with: name: pie-${{ github.sha }}.phar diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index d8e1a5c..9f251c7 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -109,4 +109,9 @@ jobs: - unit-tests - coding-standards - static-analysis - uses: ./.github/workflows/release-unsigned-phar.yml + # See build-phar.yml for a list of the permissions and why they are needed + permissions: + contents: read + id-token: write + attestations: write + uses: ./.github/workflows/build-phar.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index b095dc6..5bde9d5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -19,10 +19,14 @@ concurrency: jobs: build-phar: - uses: ./.github/workflows/release-unsigned-phar.yml + # See build-phar.yml for a list of the permissions and why they are needed + permissions: + contents: read + id-token: write + attestations: write + uses: ./.github/workflows/build-phar.yml - # Build job - build: + build-docs-package: runs-on: ubuntu-latest needs: - build-phar @@ -35,6 +39,10 @@ jobs: uses: actions/download-artifact@v4 with: name: pie-${{ github.sha }}.phar + - name: Verify the PHAR + env: + GH_TOKEN: ${{ github.token }} + run: gh attestation verify pie.phar --repo ${{ github.repository }} - name: Copy PHAR into docs run: cp pie.phar docs-package/pie-nightly.phar - name: Upload artifact @@ -42,13 +50,12 @@ jobs: with: path: docs-package - # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest - needs: build + needs: build-docs-package permissions: contents: read # pages:write is required to deploy to GitHub pages. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 228e584..e2df36b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: "Release" +name: "Publish the PHAR for Releases" on: release: @@ -9,58 +9,32 @@ permissions: contents: read jobs: + build-phar: + # See build-phar.yml for a list of the permissions and why they are needed + permissions: + contents: read + id-token: write + attestations: write + uses: ./.github/workflows/build-phar.yml + release-phar: - runs-on: ${{ matrix.operating-system }} - strategy: - matrix: - operating-system: - - ubuntu-latest - php-versions: - - '8.1' + runs-on: ubuntu-latest + needs: + - build-phar permissions: # contents:write is required to upload the binaries to the release. contents: write - # id-token:write is required for build provenance attestation. - id-token: write - # attestations:write is required for build provenance attestation. - attestations: write steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - coverage: none - tools: composer, box - php-version: "${{ matrix.php-version }}" - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - uses: ramsey/composer-install@v3 - - name: Build PHAR - run: box compile - - name: Check the PHAR executes - run: php pie.phar --version - - name: Import GPG key - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_SIGNING_KEY }} - passphrase: ${{ secrets.GPG_SIGNING_KEY_PASSPHRASE }} - - name: Sign the PHAR - run: | - gpg --local-user asgrim+pie-releases@php.net \ - --batch \ - --yes \ - --passphrase="${{ secrets.GPG_SIGNING_KEY_PASSPHRASE }}" \ - --detach-sign \ - --output pie.phar.asc \ - pie.phar - - name: Generate build provenance attestation - uses: actions/attest-build-provenance@v1 + - name: Fetch built PHAR from artifacts + uses: actions/download-artifact@v4 with: - subject-path: '${{ github.workspace }}/pie.phar' + name: pie-${{ github.sha }}.phar + - name: Verify the PHAR + env: + GH_TOKEN: ${{ github.token }} + run: gh attestation verify pie.phar --repo ${{ github.repository }} - name: Upload binaries to release uses: softprops/action-gh-release@v2 if: ${{startsWith(github.ref, 'refs/tags/') }} with: - files: | - pie.phar - pie.phar.asc + files: pie.phar diff --git a/README.md b/README.md index 799553b..eb3688c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ please read [extension-maintainers](./docs/extension-maintainers.md). - Download `pie.phar` either: - [latest stable release](https://github.com/php/pie/releases) - [latest unstable nightly](https://php.github.io/pie/pie-nightly.phar) -- Validate the signature in `pie.phar.asc` +- Verify the PHAR's source with `gh attestation verify pie.phar --repo php/pie` - You may then invoke PIE with `php pie.phar ` Further installation details can be found in the [usage](./docs/usage.md) docs. diff --git a/docs/usage.md b/docs/usage.md index 6823594..764a9b1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -9,9 +9,7 @@ order: 2 ### Manual installation - Download `pie.phar` from the [latest releases](https://github.com/php/pie/releases) -- Validate the signature in `pie.phar.asc` - - You can fetch the public key with `gpg --recv-key 343F8427AD6B48FF` - - Then you can verify the release with `gpg --verify pie.phar.asc pie.phar` +- Verify the PHAR's source with `gh attestation verify pie.phar --repo php/pie` - You may then invoke PIE with `php pie.phar ` - Optionally, copy `pie.phar` into your `$PATH`, e.g. `cp pie.phar /usr/local/bin/pie` - If you copy PIE into your `$PATH`, you may then invoke PIE with `pie ` From 41a9bd42d16c1b1d30684d10eb8de70c5d2c8e3e Mon Sep 17 00:00:00 2001 From: James Titcumb Date: Wed, 27 Nov 2024 09:25:13 +0000 Subject: [PATCH 2/2] Do not generate provenance on PR builds It does not make sense to do so; nor do PR submitters have permission to do so. We can't write attestations to `php/pie` in an unprivileged context, otherwise anyone could send a PR with malicious code, store attestation that `php/pie` built the PHAR, and it would look genuine. --- .github/workflows/build-phar.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build-phar.yml b/.github/workflows/build-phar.yml index 1a29eac..91209ad 100644 --- a/.github/workflows/build-phar.yml +++ b/.github/workflows/build-phar.yml @@ -48,6 +48,12 @@ jobs: - name: Check the PHAR executes run: php pie.phar --version - name: Generate build provenance attestation + # It does not make sense to do this for PR builds, nor do contributors + # have permission to do. We can't write attestations to `php/pie` in an + # unprivileged context, otherwise anyone could send a PR with malicious + # code, which would store attestation that `php/pie` built the PHAR, and + # it would look genuine. So this should NOT run for PR builds. + if: github.event_name != 'pull_request' uses: actions/attest-build-provenance@v1 with: subject-path: '${{ github.workspace }}/pie.phar'