From 7f622c722ab52825bb19fbbc348951fcf2ec43f5 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:32:42 +0100 Subject: [PATCH 1/3] 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 0000000..f9918c4 --- /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 a31e88ded059f4abb2916ef9e1262e9b35661769 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:32:42 +0100 Subject: [PATCH 2/3] fix(ci): resolve zizmor findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - excessive-permissions: pages: write and id-token: write were granted workflow-wide, so the build job, which runs on every pull request, got them too. They now sit on the deploy job only, which runs on main and is the only job that publishes. - artipacked: checkouts do not persist credentials. No job runs a git operation after checkout. - dependabot-cooldown: npm updates wait 7 days too, 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/ci.yml | 10 +++++++--- .github/workflows/config-docs-in-sync.yml | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d33b192..3691016 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,6 +12,8 @@ updates: schedule: interval: "weekly" day: "monday" + cooldown: + default-days: 7 open-pull-requests-limit: 5 # `include: scope` makes Dependabot append the scope itself -> chore(deps): # for runtime deps and chore(deps-dev): for dev deps. The scope must NOT be diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1b697fb..68a7d9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,11 +5,8 @@ on: branches: [main] pull_request: -# Allow the deploy job to publish to GitHub Pages. permissions: contents: read - pages: write - id-token: write jobs: build: @@ -25,6 +22,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Node.js uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 @@ -61,6 +60,11 @@ jobs: concurrency: group: pages cancel-in-progress: false + # Only the deploy job publishes to GitHub Pages; the build, which runs on + # pull requests, keeps the read-only token. + permissions: + pages: write + id-token: write environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} diff --git a/.github/workflows/config-docs-in-sync.yml b/.github/workflows/config-docs-in-sync.yml index 43e66c3..971e414 100644 --- a/.github/workflows/config-docs-in-sync.yml +++ b/.github/workflows/config-docs-in-sync.yml @@ -44,12 +44,15 @@ jobs: steps: - name: Checkout docs uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Checkout config-to-docs uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: owncloud/config-to-docs path: .config-to-docs + persist-credentials: false # Deliberately unpinned. This check asks "do the committed pages match # what a maintainer running ctd.sh today would produce", so it has to # track the current generator. The composer deps below are pinned From aa85ec81d40d4e0a0d7e19748c5336873155d919 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:44:37 +0100 Subject: [PATCH 3/3] fix(ci): address review of the zizmor rollout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the zizmor caller's concurrency comment changes: GitHub keeps one queued run per group, so for non-pull-request events a newer run still replaces a queued one; the comment now says so instead of claiming only pull request runs are superseded. The deploy job keeps contents: read alongside pages/id-token write, the token it had before, since a narrower one would only surface after merge. Correction to the previous commit message: config-docs-in-sync does run git ls-remote and git clone after checkout, but only against public repositories, which need no credentials. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com> --- .github/workflows/ci.yml | 1 + .github/workflows/zizmor.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68a7d9f..c4191bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,6 +63,7 @@ jobs: # Only the deploy job publishes to GitHub Pages; the build, which runs on # pull requests, keeps the read-only token. permissions: + contents: read pages: write id-token: write environment: diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index f9918c4..8b59595 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,7 +19,8 @@ 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. +# displace the weekly run. Running pull request runs are cancelled by newer +# ones; for other events GitHub still replaces a queued run with a newer one. concurrency: group: zizmor-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: ${{ github.event_name == 'pull_request' }}