From 7f95439bc22cdf5158e69bea60ed3c41122e12f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Thu, 1 Oct 2026 08:40:42 +0000 Subject: [PATCH] :construction_worker: Declare least-privilege workflow permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an explicit permissions block to every workflow that relied on the repository default. Entry points that only call reusable workflows get permissions: {} and grant each call what the called workflow needs: contents: read for the bundle and docker builds, contents: write for the release, nothing for the admin-console dispatch (it uses its own token). Workflows that check out code get contents: read; the commit checker also gets pull-requests: read to list the PR commits. Signed-off-by: David Barragán Merino --- .github/workflows/auto-label.yml | 2 ++ .github/workflows/build-adhoc.yml | 7 ++++++ .github/workflows/build-bundle.yml | 3 +++ .github/workflows/build-develop.yml | 7 ++++++ .../workflows/build-docker-admin-console.yml | 2 ++ .github/workflows/build-docker-devenv.yml | 3 +++ .github/workflows/build-docker.yml | 3 +++ .github/workflows/build-staging.yml | 7 ++++++ .github/workflows/build-tag.yml | 10 ++++++++ .github/workflows/build-tmp-tokens.yml | 6 +++++ .github/workflows/commit-checker.yml | 4 ++++ .github/workflows/plugins-deploy-packages.yml | 3 +++ .github/workflows/tests-backend.yml | 3 +++ .github/workflows/tests-common.yml | 3 +++ .github/workflows/tests-e2e.yml | 3 +++ .github/workflows/tests-exporter.yml | 3 +++ .github/workflows/tests-frontend.yml | 3 +++ .github/workflows/tests-library.yml | 3 +++ .github/workflows/tests-mcp.yml | 3 +++ .github/workflows/tests-plugins.yml | 3 +++ .github/workflows/tests-wasm.yml | 3 +++ .github/zizmor.yml | 24 ------------------- 22 files changed, 84 insertions(+), 24 deletions(-) diff --git a/.github/workflows/auto-label.yml b/.github/workflows/auto-label.yml index 6b32b61c52..7bbfba22fb 100644 --- a/.github/workflows/auto-label.yml +++ b/.github/workflows/auto-label.yml @@ -6,6 +6,8 @@ on: pull_request_target: types: [opened] +permissions: {} + jobs: triage: runs-on: ubuntu-latest diff --git a/.github/workflows/build-adhoc.yml b/.github/workflows/build-adhoc.yml index f5f9b88854..1dcb83bbb5 100644 --- a/.github/workflows/build-adhoc.yml +++ b/.github/workflows/build-adhoc.yml @@ -20,8 +20,12 @@ on: required: false default: false +permissions: {} + jobs: build-bundle: + permissions: + contents: read uses: ./.github/workflows/build-bundle.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -35,6 +39,8 @@ jobs: build-docker: needs: build-bundle + permissions: + contents: read uses: ./.github/workflows/build-docker.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -54,6 +60,7 @@ jobs: force: ${{ inputs.force }} build-docker-admin-console: + permissions: {} uses: ./.github/workflows/build-docker-admin-console.yml secrets: ORG_WORKFLOW_TOKEN: ${{ secrets.ORG_WORKFLOW_TOKEN }} diff --git a/.github/workflows/build-bundle.yml b/.github/workflows/build-bundle.yml index 752ff096f6..1172790408 100644 --- a/.github/workflows/build-bundle.yml +++ b/.github/workflows/build-bundle.yml @@ -49,6 +49,9 @@ concurrency: group: build-bundle-${{ inputs.gh_ref }} cancel-in-progress: true +permissions: + contents: read + jobs: # ── 1. Decide whether there is anything to build ─────────────────────── check: diff --git a/.github/workflows/build-develop.yml b/.github/workflows/build-develop.yml index 942f840576..e808f38384 100644 --- a/.github/workflows/build-develop.yml +++ b/.github/workflows/build-develop.yml @@ -18,8 +18,12 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: true +permissions: {} + jobs: build-bundle: + permissions: + contents: read uses: ./.github/workflows/build-bundle.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -33,6 +37,8 @@ jobs: build-docker: needs: build-bundle + permissions: + contents: read uses: ./.github/workflows/build-docker.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -52,6 +58,7 @@ jobs: force: ${{ inputs.force || false }} build-docker-admin-console: + permissions: {} uses: ./.github/workflows/build-docker-admin-console.yml secrets: ORG_WORKFLOW_TOKEN: ${{ secrets.ORG_WORKFLOW_TOKEN }} diff --git a/.github/workflows/build-docker-admin-console.yml b/.github/workflows/build-docker-admin-console.yml index e193d47704..3d1ef04008 100644 --- a/.github/workflows/build-docker-admin-console.yml +++ b/.github/workflows/build-docker-admin-console.yml @@ -39,6 +39,8 @@ on: description: 'Token with Actions write access on penpot-nitrate' required: true +permissions: {} + jobs: build-nitrate-docker: runs-on: ubuntu-latest diff --git a/.github/workflows/build-docker-devenv.yml b/.github/workflows/build-docker-devenv.yml index 39d3c2594f..87856225bb 100644 --- a/.github/workflows/build-docker-devenv.yml +++ b/.github/workflows/build-docker-devenv.yml @@ -3,6 +3,9 @@ name: DevEnv Docker Image Builder on: workflow_dispatch: +permissions: + contents: read + jobs: build-and-push: name: Build and push DevEnv Docker image diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index f7348a0998..a590606585 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -70,6 +70,9 @@ env: # missing (e.g. if runners ever move to separate machines). BUNDLE_CACHE: /var/tmp/penpot-bundle-cache +permissions: + contents: read + jobs: # ── 1. Resolve the build key and check the whole set at once ─────────── prepare: diff --git a/.github/workflows/build-staging.yml b/.github/workflows/build-staging.yml index 3fb417c801..2b8d7a8e4c 100644 --- a/.github/workflows/build-staging.yml +++ b/.github/workflows/build-staging.yml @@ -18,8 +18,12 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: true +permissions: {} + jobs: build-bundle: + permissions: + contents: read uses: ./.github/workflows/build-bundle.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -33,6 +37,8 @@ jobs: build-docker: needs: build-bundle + permissions: + contents: read uses: ./.github/workflows/build-docker.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -52,6 +58,7 @@ jobs: force: ${{ inputs.force || false }} build-docker-admin-console: + permissions: {} uses: ./.github/workflows/build-docker-admin-console.yml secrets: ORG_WORKFLOW_TOKEN: ${{ secrets.ORG_WORKFLOW_TOKEN }} diff --git a/.github/workflows/build-tag.yml b/.github/workflows/build-tag.yml index 9b0b0fcbb3..c2fd48671d 100644 --- a/.github/workflows/build-tag.yml +++ b/.github/workflows/build-tag.yml @@ -21,8 +21,12 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: false +permissions: {} + jobs: build-bundle: + permissions: + contents: read uses: ./.github/workflows/build-bundle.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -36,6 +40,8 @@ jobs: build-docker: needs: build-bundle + permissions: + contents: read uses: ./.github/workflows/build-docker.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -53,6 +59,7 @@ jobs: force: ${{ inputs.force || false }} build-docker-admin-console: + permissions: {} uses: ./.github/workflows/build-docker-admin-console.yml secrets: ORG_WORKFLOW_TOKEN: ${{ secrets.ORG_WORKFLOW_TOKEN }} @@ -62,6 +69,7 @@ jobs: notify: name: Notifications + permissions: {} runs-on: ubuntu-latest needs: - build-docker @@ -82,6 +90,8 @@ jobs: needs: - build-docker - build-docker-admin-console + permissions: + contents: write uses: ./.github/workflows/release.yml secrets: AWS_REGION: ${{ secrets.AWS_REGION }} diff --git a/.github/workflows/build-tmp-tokens.yml b/.github/workflows/build-tmp-tokens.yml index 68eeae1706..28802b1ccc 100644 --- a/.github/workflows/build-tmp-tokens.yml +++ b/.github/workflows/build-tmp-tokens.yml @@ -9,8 +9,12 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: true +permissions: {} + jobs: build-bundle: + permissions: + contents: read uses: ./.github/workflows/build-bundle.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -23,6 +27,8 @@ jobs: build-docker: needs: build-bundle + permissions: + contents: read uses: ./.github/workflows/build-docker.yml secrets: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} diff --git a/.github/workflows/commit-checker.yml b/.github/workflows/commit-checker.yml index c876d10160..bd4a9f0572 100644 --- a/.github/workflows/commit-checker.yml +++ b/.github/workflows/commit-checker.yml @@ -20,6 +20,10 @@ on: - develop - staging +permissions: + contents: read + pull-requests: read + jobs: check-commit-message: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/plugins-deploy-packages.yml b/.github/workflows/plugins-deploy-packages.yml index 218620983f..11650fd5ef 100644 --- a/.github/workflows/plugins-deploy-packages.yml +++ b/.github/workflows/plugins-deploy-packages.yml @@ -21,6 +21,9 @@ on: - staging - main +permissions: + contents: read + jobs: detect-changes: runs-on: ubuntu-latest diff --git a/.github/workflows/tests-backend.yml b/.github/workflows/tests-backend.yml index 1557a8685a..6a447d5737 100644 --- a/.github/workflows/tests-backend.yml +++ b/.github/workflows/tests-backend.yml @@ -28,6 +28,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-backend: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-common.yml b/.github/workflows/tests-common.yml index b622958277..a4d32c39b1 100644 --- a/.github/workflows/tests-common.yml +++ b/.github/workflows/tests-common.yml @@ -26,6 +26,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-common: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-e2e.yml b/.github/workflows/tests-e2e.yml index 07e1cc47a9..0f6f0f8765 100644 --- a/.github/workflows/tests-e2e.yml +++ b/.github/workflows/tests-e2e.yml @@ -86,6 +86,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || inputs.gh_ref || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: # ── 1. Build the frontend bundle once ────────────────────────────────── build-bundle: diff --git a/.github/workflows/tests-exporter.yml b/.github/workflows/tests-exporter.yml index 8441af3a75..db32e3f59c 100644 --- a/.github/workflows/tests-exporter.yml +++ b/.github/workflows/tests-exporter.yml @@ -30,6 +30,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-exporter: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-frontend.yml b/.github/workflows/tests-frontend.yml index 8fcfdc8066..eff25d11df 100644 --- a/.github/workflows/tests-frontend.yml +++ b/.github/workflows/tests-frontend.yml @@ -30,6 +30,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-frontend: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-library.yml b/.github/workflows/tests-library.yml index df2c478ca1..5a714705fb 100644 --- a/.github/workflows/tests-library.yml +++ b/.github/workflows/tests-library.yml @@ -28,6 +28,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-library: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-mcp.yml b/.github/workflows/tests-mcp.yml index 68ff0584bd..50dc8a6806 100644 --- a/.github/workflows/tests-mcp.yml +++ b/.github/workflows/tests-mcp.yml @@ -24,6 +24,9 @@ on: paths: - 'mcp/**' +permissions: + contents: read + jobs: test-mcp: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-plugins.yml b/.github/workflows/tests-plugins.yml index 180f125489..01ed31eccf 100644 --- a/.github/workflows/tests-plugins.yml +++ b/.github/workflows/tests-plugins.yml @@ -26,6 +26,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-plugins: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/workflows/tests-wasm.yml b/.github/workflows/tests-wasm.yml index fdbc8820ff..135d65a045 100644 --- a/.github/workflows/tests-wasm.yml +++ b/.github/workflows/tests-wasm.yml @@ -26,6 +26,9 @@ concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +permissions: + contents: read + jobs: test-render-wasm: if: ${{ !github.event.pull_request.draft }} diff --git a/.github/zizmor.yml b/.github/zizmor.yml index d4681e9f17..fa7ba76bf6 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -22,30 +22,6 @@ rules: ignore: - auto-label.yml - commit-checker.yml - # Declare least-privilege `permissions:` per workflow/job. - excessive-permissions: - ignore: - - auto-label.yml - - build-adhoc.yml - - build-bundle.yml - - build-develop.yml - - build-docker-admin-console.yml - - build-docker-devenv.yml - - build-docker.yml - - build-staging.yml - - build-tag.yml - - build-tmp-tokens.yml - - commit-checker.yml - - plugins-deploy-packages.yml - - tests-backend.yml - - tests-common.yml - - tests-e2e.yml - - tests-exporter.yml - - tests-frontend.yml - - tests-library.yml - - tests-mcp.yml - - tests-plugins.yml - - tests-wasm.yml # Scope GitHub App tokens. github-app: ignore: