diff --git a/.github/poutine.yml b/.github/poutine.yml new file mode 100644 index 00000000..e35805b5 --- /dev/null +++ b/.github/poutine.yml @@ -0,0 +1,4 @@ +skip: + # Every third-party action is pinned to a full commit SHA, which is what protects against + # a compromised upstream; whether the publisher is a "verified creator" adds nothing on top. + - rule: github_action_from_unverified_creator_used diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d7af661..7ab4af49 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,6 +12,9 @@ concurrency: group: build-${{ github.head_ref || github.run_id }} # will be canceled on subsequent pushes in pull requests but not branches cancel-in-progress: true +permissions: + contents: read + jobs: lint: name: "Lint" @@ -37,6 +40,8 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Install PHP" uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # v2 @@ -68,10 +73,13 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Checkout build-cs" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false repository: "phpstan/build-cs" path: "build-cs" ref: "2.x" @@ -141,6 +149,8 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Install PHP" uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # v2 @@ -159,7 +169,7 @@ jobs: run: "composer update --no-interaction --no-progress" - name: "Update packages" - run: ${{ matrix.update-packages }} + run: ${{ matrix.update-packages }} # zizmor: ignore[template-injection] the script is defined by the matrix above - name: "Tests" run: "make tests" @@ -184,15 +194,19 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Checkout build-infection" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + persist-credentials: false repository: "phpstan/build-infection" path: "build-infection" ref: "1.x" - - uses: ./build-infection/.github/actions/setup-php + # The action comes from the phpstan/build-infection checkout above, which the $/ self-repository syntax cannot load + - uses: ./build-infection/.github/actions/setup-php # zizmor: ignore[self-repository] with: php-version: "${{ matrix.php-version }}" php-extensions: pdo, mysqli, pgsql, pdo_mysql, pdo_pgsql, pdo_sqlite, mongodb @@ -260,6 +274,8 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Install PHP" uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # v2 @@ -273,7 +289,7 @@ jobs: run: "composer update --no-interaction --no-progress" - name: "Update packages" - run: ${{ matrix.update-packages }} + run: ${{ matrix.update-packages }} # zizmor: ignore[template-injection] the script is defined by the matrix above - name: "PHPStan" run: "make phpstan" @@ -292,6 +308,8 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Install PHP" uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # v2 @@ -299,7 +317,7 @@ jobs: coverage: "none" php-version: "8.5" - - uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # v4.0.0 + - uses: "ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda" # 4.0.0 - name: "Name Collision Detector" run: "make name-collision" diff --git a/.github/workflows/create-tag.yml b/.github/workflows/create-tag.yml index 2abdb94c..66d3e295 100644 --- a/.github/workflows/create-tag.yml +++ b/.github/workflows/create-tag.yml @@ -15,6 +15,13 @@ on: - patch - minor +concurrency: + group: create-tag + cancel-in-progress: true + +permissions: + contents: read + jobs: create-tag: name: "Create tag" @@ -25,7 +32,8 @@ jobs: with: egress-policy: audit - - name: "Checkout" + # Credentials must stay persisted: rickstaa/action-create-tag pushes the tag with them + - name: "Checkout" # zizmor: ignore[artipacked] uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 diff --git a/.github/workflows/lint-workflows.yml b/.github/workflows/lint-workflows.yml index 02ad5343..8520319d 100644 --- a/.github/workflows/lint-workflows.yml +++ b/.github/workflows/lint-workflows.yml @@ -8,10 +8,15 @@ on: branches: - "2.1.x" +concurrency: + group: lint-workflows-${{ github.head_ref || github.run_id }} # will be canceled on subsequent pushes in pull requests but not branches + cancel-in-progress: true + permissions: {} jobs: actionlint: + name: actionlint runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) @@ -20,10 +25,18 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Check workflow files + env: + ACTIONLINT_VERSION: "1.7.12" + ACTIONLINT_SHA256: "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8" run: | echo "::add-matcher::.github/actionlint-matcher.json" - bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) + curl -fsSL -o actionlint.tar.gz "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" + echo "${ACTIONLINT_SHA256} actionlint.tar.gz" | sha256sum -c - + tar -xzf actionlint.tar.gz actionlint ./actionlint -color shell: bash @@ -40,11 +53,17 @@ jobs: egress-policy: audit - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Run octoscan id: octoscan uses: synacktiv/action-octoscan@6b1cf2343893dfb9e5f75652388bd2dc83f456b0 # v1.0.0 with: filter_triggers: '' + # The only custom-ref checkouts are phpstan/build-cs and phpstan/build-infection at fixed branches, + # and the only local action comes from the phpstan/build-infection checkout. + ignore: "Use of 'actions/checkout' with a custom ref|Use of local action .\\./build-infection/" - name: Upload SARIF file to GitHub uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1 diff --git a/.github/workflows/lock-closed-issues.yml b/.github/workflows/lock-closed-issues.yml index 71b086d5..cee0cf26 100644 --- a/.github/workflows/lock-closed-issues.yml +++ b/.github/workflows/lock-closed-issues.yml @@ -4,11 +4,16 @@ on: schedule: - cron: '3 0 * * *' +concurrency: + group: lock-closed-issues + cancel-in-progress: true + permissions: contents: read jobs: lock: + name: "Lock closed issues" permissions: issues: write # for dessant/lock-threads to lock issues runs-on: ubuntu-latest diff --git a/.github/workflows/platform-test.yml b/.github/workflows/platform-test.yml index 5fbb68b3..7b2647d9 100644 --- a/.github/workflows/platform-test.yml +++ b/.github/workflows/platform-test.yml @@ -8,6 +8,10 @@ on: branches: - "2.1.x" +concurrency: + group: platform-test-${{ github.head_ref || github.run_id }} # will be canceled on subsequent pushes in pull requests but not branches + cancel-in-progress: true + permissions: contents: read @@ -49,6 +53,8 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: "Install PHP" uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # v2 @@ -63,14 +69,19 @@ jobs: - name: "Update packages" if: ${{ matrix.update-packages != '' }} - run: composer require --dev ${{ matrix.update-packages }} -W + env: + UPDATE_PACKAGES: ${{ matrix.update-packages }} + run: | + # shellcheck disable=SC2086 # UPDATE_PACKAGES is a space-separated list of packages + composer require --dev $UPDATE_PACKAGES -W - name: "Run platform matrix test" run: vendor/bin/phpunit --group=platform services: + # Platform tests deliberately run against the newest database server releases postgres: - image: "postgres:latest" + image: "postgres:latest" # zizmor: ignore[unpinned-images] env: POSTGRES_PASSWORD: "secret" POSTGRES_USER: root @@ -79,7 +90,7 @@ jobs: - "5432:5432" mysql: - image: "mysql:latest" + image: "mysql:latest" # zizmor: ignore[unpinned-images] env: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_ROOT_PASSWORD: secret diff --git a/.github/workflows/release-toot.yml b/.github/workflows/release-toot.yml index 4e8a264d..05337298 100644 --- a/.github/workflows/release-toot.yml +++ b/.github/workflows/release-toot.yml @@ -6,8 +6,15 @@ on: release: types: [published] +concurrency: + group: toot-${{ github.event.release.tag_name }} + cancel-in-progress: true + +permissions: {} + jobs: toot: + name: "Toot release" runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) diff --git a/.github/workflows/release-tweet.yml b/.github/workflows/release-tweet.yml index eb7cd955..003b3997 100644 --- a/.github/workflows/release-tweet.yml +++ b/.github/workflows/release-tweet.yml @@ -6,8 +6,15 @@ on: release: types: [published] +concurrency: + group: tweet-${{ github.event.release.tag_name }} + cancel-in-progress: true + +permissions: {} + jobs: tweet: + name: "Tweet release" runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8ea4eda..1da62b78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,6 +7,13 @@ on: tags: - '*' +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + jobs: deploy: name: "Deploy" @@ -20,6 +27,8 @@ jobs: - name: "Checkout" uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Generate changelog id: changelog @@ -27,7 +36,7 @@ jobs: with: myToken: ${{ secrets.PHPSTAN_BOT_TOKEN }} - - name: "Create release" + - name: "Create release" # zizmor: ignore[superfluous-actions] uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3 with: token: ${{ secrets.PHPSTAN_BOT_TOKEN }} diff --git a/.github/workflows/test-projects.yml b/.github/workflows/test-projects.yml index eec92e94..8c22bf6c 100644 --- a/.github/workflows/test-projects.yml +++ b/.github/workflows/test-projects.yml @@ -7,6 +7,10 @@ on: branches: - "2.1.x" +concurrency: + group: test-projects + cancel-in-progress: true + permissions: contents: read diff --git a/.github/zizmor.yml b/.github/zizmor.yml new file mode 100644 index 00000000..7b4f2dc7 --- /dev/null +++ b/.github/zizmor.yml @@ -0,0 +1,12 @@ +rules: + secrets-outside-env: + config: + # Repository-level secrets used by release automation; they are not scoped to deployment environments. + allow: + - PHPSTAN_BOT_TOKEN + - MASTODON_ACCESS_TOKEN + - TWITTER_CONSUMER_API_KEY + - TWITTER_CONSUMER_API_SECRET + - TWITTER_ACCESS_TOKEN + - TWITTER_ACCESS_TOKEN_SECRET + - REPO_ACCESS_TOKEN