From 019e052c3c03a89b3f6fffb63ce2579130ce59b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <323649642+oc-tmueller@users.noreply.github.com> Date: Mon, 26 Oct 2026 14:43:40 +0100 Subject: [PATCH 1/2] ci: add zizmor workflow audit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runs zizmor over this repository's workflows and Dependabot config on every pull request, on pushes to the default branch and weekly, through owncloud/reusable-workflows' zizmor.yml. Any finding fails the check. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com> --- .github/workflows/zizmor.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/zizmor.yml diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 00000000..f9918c4e --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,30 @@ +name: Zizmor + +on: + push: + branches: + - main + pull_request: + types: + - opened + - synchronize + - reopened + schedule: + # Weekly: online audits (known-vulnerable actions, impostor commits) can + # start failing without a code change. + - cron: '0 4 * * 1' + workflow_dispatch: + +permissions: + contents: read + +# Grouped per event, so a push to the default branch can never cancel or +# displace the weekly run; only pull request runs cancel superseded ones. +concurrency: + group: zizmor-${{ github.event_name }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + zizmor: + name: Zizmor + uses: owncloud/reusable-workflows/.github/workflows/zizmor.yml@main From c6938cb6b80ff8b28c679c2cade2137d74bacb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= <323649642+oc-tmueller@users.noreply.github.com> Date: Mon, 26 Oct 2026 14:43:40 +0100 Subject: [PATCH 2/2] fix(ci): resolve zizmor findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - github-app: each codesign-bot App token requests only what its binary uses, instead of inheriting every permission of the installation: issuer and revoker read/close/comment on/label request issues and write the ledger (contents + issues write); privrevoke only reads and writes the ledger, and crlgen the CRL (contents write). The issuer's org-wide owner: scope stays, suppressed inline: target app repos are only known at runtime (issue #35). - dangerous-triggers: crl's workflow_run trigger is suppressed inline. It re-runs main's own crlgen after a revocation and reads no artifact, ref or input from the triggering run. - artipacked: checkouts do not persist credentials. Nothing runs git after checkout; ledger and CRL writes go through the Contents API. - dependabot-cooldown: gomod updates wait 7 days, as github-actions already does. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com> --- .github/dependabot.yml | 2 ++ .github/workflows/crl.yml | 5 ++++- .github/workflows/issuer.yml | 6 +++++- .github/workflows/pages.yml | 2 ++ .github/workflows/privileged-revocation.yml | 3 +++ .github/workflows/revocation.yml | 4 ++++ .github/workflows/validate.yml | 2 ++ 7 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index f6f9e596..a95118e4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,5 +16,7 @@ updates: directory: / schedule: interval: weekly + cooldown: + default-days: 7 commit-message: prefix: build diff --git a/.github/workflows/crl.yml b/.github/workflows/crl.yml index 9fc0c0dc..9725785d 100644 --- a/.github/workflows/crl.yml +++ b/.github/workflows/crl.yml @@ -7,7 +7,7 @@ on: schedule: - cron: "0 0 * * *" # daily; keeps nextUpdate fresh (spec §3.1) workflow_dispatch: - workflow_run: + workflow_run: # zizmor: ignore[dangerous-triggers] runs main's own crlgen and reads nothing from the triggering run workflows: [revocation, privileged-revocation] types: [completed] @@ -29,6 +29,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable @@ -41,6 +43,7 @@ jobs: with: app-id: ${{ secrets.BOT_APP_ID }} private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} + permission-contents: write - name: Generate and publish CRL env: GITHUB_TOKEN: ${{ steps.apptoken.outputs.token }} diff --git a/.github/workflows/issuer.yml b/.github/workflows/issuer.yml index 02cae42f..d870814b 100644 --- a/.github/workflows/issuer.yml +++ b/.github/workflows/issuer.yml @@ -28,6 +28,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable @@ -47,7 +49,9 @@ jobs: with: app-id: ${{ secrets.BOT_APP_ID }} private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} + owner: ${{ github.repository_owner }} # zizmor: ignore[github-app] target app repos are only known at runtime (issue #35) + permission-contents: write + permission-issues: write - name: Run issuer env: GITHUB_TOKEN: ${{ steps.apptoken.outputs.token }} diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 1dd6bdde..540cc382 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -41,6 +41,8 @@ jobs: url: ${{ steps.deploy.outputs.page_url }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 # Stage ONLY the CRL files (design §13). This explicit copy is the single # guarantee that the Pages site contains nothing but the CRL(s) — no repo diff --git a/.github/workflows/privileged-revocation.yml b/.github/workflows/privileged-revocation.yml index 941eda00..1a094034 100644 --- a/.github/workflows/privileged-revocation.yml +++ b/.github/workflows/privileged-revocation.yml @@ -40,6 +40,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable @@ -50,6 +52,7 @@ jobs: with: app-id: ${{ secrets.BOT_APP_ID }} private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} + permission-contents: write - name: Run privileged revocation env: GITHUB_TOKEN: ${{ steps.apptoken.outputs.token }} diff --git a/.github/workflows/revocation.yml b/.github/workflows/revocation.yml index d96acf31..9b280498 100644 --- a/.github/workflows/revocation.yml +++ b/.github/workflows/revocation.yml @@ -29,6 +29,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable @@ -39,6 +41,8 @@ jobs: with: app-id: ${{ secrets.BOT_APP_ID }} private-key: ${{ secrets.BOT_APP_PRIVATE_KEY }} + permission-contents: write + permission-issues: write - name: Run revoker env: GITHUB_TOKEN: ${{ steps.apptoken.outputs.token }} diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 4a9fbd55..1327a8cb 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -14,6 +14,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: stable