From f3722f1e01623a674bcd9cf2ead247284b389187 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 10:20:40 +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 | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 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 00000000000..938b3736841 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,28 @@ +name: Zizmor + +on: + push: + branches: + - master + 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 + +concurrency: + group: zizmor-${{ github.ref }} + cancel-in-progress: true + +jobs: + zizmor: + name: Zizmor + uses: owncloud/reusable-workflows/.github/workflows/zizmor.yml@main From 3f44575bb86fccbd4fe31749670a641cb88106a5 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 10:20:41 +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 - dependabot-cooldown: composer and npm updates wait 7 days too, as github-actions already does. - artipacked: checkouts do not persist credentials. No job runs a git operation after checkout. - self-repository: the local reusable workflows are called as $/... instead of ./..., which files written to the workspace at runtime cannot redirect. - ref-version-mismatch: setup-php's tag is 2.40.0, without the v. - unpinned-images: suppressed inline. The database image tags come from the caller's databases input; the Oracle image is tag-pinned, and a digest would also freeze its security patches. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com> --- .github/dependabot.yml | 8 ++++++++ .github/workflows/acceptance.yml | 10 ++++++--- .github/workflows/ci.yml | 26 +++++++++++++----------- .github/workflows/js-unit.yml | 2 ++ .github/workflows/lint-and-codestyle.yml | 4 +++- .github/workflows/nightly.yml | 2 +- .github/workflows/php-unit.yml | 9 ++++---- 7 files changed, 40 insertions(+), 21 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 050cf691740..e9248aaaf3e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,6 +7,8 @@ updates: day: sunday time: '22:00' timezone: Etc/UTC + cooldown: + default-days: 7 open-pull-requests-limit: 5 groups: minor-and-patch: @@ -26,6 +28,8 @@ updates: day: sunday time: '22:00' timezone: Etc/UTC + cooldown: + default-days: 7 open-pull-requests-limit: 5 groups: minor-and-patch: @@ -40,6 +44,8 @@ updates: day: sunday time: '22:00' timezone: Etc/UTC + cooldown: + default-days: 7 open-pull-requests-limit: 5 groups: minor-and-patch: @@ -57,6 +63,8 @@ updates: day: sunday time: '22:00' timezone: Etc/UTC + cooldown: + default-days: 7 open-pull-requests-limit: 5 ignore: - dependency-name: "*" diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 5c0d23c9dd7..0b8e887caaf 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -90,7 +90,7 @@ jobs: services: mysql: - image: >- + image: >- # zizmor: ignore[unpinned-images] the tag comes from the caller's databases input ${{ case(startsWith(matrix.database,'mysql:') || startsWith(matrix.database,'mariadb:'), matrix.database, inputs.federated-folder != '', 'mariadb:10.6', '') }} env: MYSQL_ROOT_PASSWORD: password @@ -105,7 +105,7 @@ jobs: ports: - 3306:3306 postgres: - image: ${{ case(startsWith(matrix.database,'postgres:'), matrix.database, '') }} + image: ${{ case(startsWith(matrix.database,'postgres:'), matrix.database, '') }} # zizmor: ignore[unpinned-images] the tag comes from the caller's databases input env: POSTGRES_DB: owncloud POSTGRES_USER: owncloud @@ -135,12 +135,14 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: owncloud/core + persist-credentials: false - name: Checkout testing app uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: path: apps/testing repository: owncloud/testing + persist-credentials: false - name: Setup testing app run: | @@ -154,6 +156,7 @@ jobs: path: apps/${{ inputs.additional-app }} repository: owncloud/${{ inputs.additional-app }} token: ${{ inputs.additional-app-github-token || github.token }} + persist-credentials: false - name: Setup additional app if: ${{ inputs.additional-app != '' }} @@ -175,7 +178,7 @@ jobs: sudo apt-get install -y -o Acquire::Retries=3 "$ADDITIONAL_PACKAGES" - name: Setup PHP - uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # v2.40.0 + uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0 with: php-version: ${{ matrix.php }} extensions: apcu, ctype, curl, exif, fileinfo, gd, iconv, imagick, intl, json, mbstring, memcached, pdo, posix, simplexml, xml, zip, smbclient, ldap, krb5 @@ -190,6 +193,7 @@ jobs: with: path: apps/files_primary_s3 repository: owncloud/files_primary_s3 + persist-credentials: false - name: Setup files_primary_s3 app if: ${{ inputs.use-scality-s3 }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06292d4c324..0dcb9aae6b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,11 +24,11 @@ jobs: js-unit: name: JavaScript Unit - uses: ./.github/workflows/js-unit.yml + uses: $/.github/workflows/js-unit.yml php-unit: name: PHP Unit - uses: ./.github/workflows/php-unit.yml + uses: $/.github/workflows/php-unit.yml with: php-versions: '["8.3"]' @@ -36,7 +36,7 @@ jobs: # Same display name as php-unit so both appear in one group of checks. It # stays a separate job because the acceptance jobs must not need Oracle. name: PHP Unit - uses: ./.github/workflows/php-unit.yml + uses: $/.github/workflows/php-unit.yml with: php-versions: '["8.3"]' databases: '["oracle:23"]' @@ -47,6 +47,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Validate changelog entries uses: actionhippie/calens@2008d3a7a90cf05a2a001a3d47cac06cb1b74617 # v1.14.2 @@ -55,7 +57,7 @@ jobs: if: ${{ !contains(github.event.pull_request.title, 'full-ci') }} name: API Smoke Tests needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-api-tests: true server-folder: 'server' @@ -74,7 +76,7 @@ jobs: # There is no full-ci variant on S3, so this runs on every PR. name: API Smoke Tests on S3 needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-api-tests: true server-folder: 'server' @@ -94,7 +96,7 @@ jobs: if: contains(github.event.pull_request.title, 'full-ci') name: API Tests needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-api-tests: true server-folder: 'server' @@ -127,7 +129,7 @@ jobs: if: contains(github.event.pull_request.title, 'full-ci') name: API Tests Notifications needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-api-tests: true server-folder: 'server' @@ -138,7 +140,7 @@ jobs: if: contains(github.event.pull_request.title, 'full-ci') name: API Tests Previews needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-api-tests: true additional-packages: 'imagemagick' @@ -149,7 +151,7 @@ jobs: if: contains(github.event.pull_request.title, 'full-ci') name: API Tests Federation needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-api-tests: true server-folder: 'server' @@ -160,7 +162,7 @@ jobs: if: ${{ !contains(github.event.pull_request.title, 'full-ci') }} name: CLI Smoke Tests needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-cli-tests: true use-email-server: true @@ -171,7 +173,7 @@ jobs: if: contains(github.event.pull_request.title, 'full-ci') name: CLI Tests needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-cli-tests: true server-folder: 'server' @@ -181,7 +183,7 @@ jobs: if: contains(github.event.pull_request.title, 'full-ci') name: CLI Tests with Email needs: [semantic-git-messages, php-unit, calens] - uses: ./.github/workflows/acceptance.yml + uses: $/.github/workflows/acceptance.yml with: do-cli-tests: true use-email-server: true diff --git a/.github/workflows/js-unit.yml b/.github/workflows/js-unit.yml index 29a163d47b2..3087075d41d 100644 --- a/.github/workflows/js-unit.yml +++ b/.github/workflows/js-unit.yml @@ -12,6 +12,8 @@ jobs: steps: - name: Clone owncloud/core uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Node.js uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 diff --git a/.github/workflows/lint-and-codestyle.yml b/.github/workflows/lint-and-codestyle.yml index ce05c1af1bf..1019907af92 100644 --- a/.github/workflows/lint-and-codestyle.yml +++ b/.github/workflows/lint-and-codestyle.yml @@ -28,9 +28,11 @@ jobs: steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # v2.40.0 + uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0 with: php-version: ${{ matrix.php-version }} extensions: curl, gd, json, xml, zip diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 6cc39ecd4ce..bdeabd10d00 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -16,7 +16,7 @@ concurrency: jobs: php-unit-oracle: name: PHP Unit Oracle - uses: ./.github/workflows/php-unit.yml + uses: $/.github/workflows/php-unit.yml with: php-versions: '["8.3"]' databases: '["oracle:23"]' diff --git a/.github/workflows/php-unit.yml b/.github/workflows/php-unit.yml index f25d8395986..290f5755134 100644 --- a/.github/workflows/php-unit.yml +++ b/.github/workflows/php-unit.yml @@ -26,7 +26,7 @@ jobs: services: mysql: - image: >- + image: >- # zizmor: ignore[unpinned-images] the tag comes from the caller's databases input ${{ case(startsWith(matrix.database,'mysql:') || startsWith(matrix.database,'mariadb:'), matrix.database, '') }} env: MYSQL_ROOT_PASSWORD: password @@ -41,7 +41,7 @@ jobs: ports: - 3306:3306 postgres: - image: ${{ case(startsWith(matrix.database,'postgres:'), matrix.database, '') }} + image: ${{ case(startsWith(matrix.database,'postgres:'), matrix.database, '') }} # zizmor: ignore[unpinned-images] the tag comes from the caller's databases input env: POSTGRES_DB: owncloud POSTGRES_USER: owncloud @@ -52,7 +52,7 @@ jobs: # Oracle Database Free 23ai. The APP_USER schema is created inside the # FREEPDB1 pluggable database, so a connect string using SERVICE_NAME is # required - a plain host plus database name would target the CDB root. - image: >- + image: >- # zizmor: ignore[unpinned-images] tag-pinned; a digest would also freeze Oracle's security patches ${{ case(startsWith(matrix.database,'oracle:'), 'gvenzl/oracle-free:23-slim-faststart', '') }} env: ORACLE_PASSWORD: owncloud @@ -71,9 +71,10 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: owncloud/core + persist-credentials: false - name: Setup PHP - uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # v2.40.0 + uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0 with: php-version: ${{ matrix.php }} extensions: curl, gd, json, xml, zip, imagick${{ case(startsWith(matrix.database,'oracle:'), ', oci8', '') }} From 92f7883810d738389151ca5d299c3f7c82456234 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 13:01:32 +0100 Subject: [PATCH 3/3] fix(ci): keep scheduled zizmor runs, correct an ignore reason MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only pull request runs of the zizmor audit cancel each other now; a push to master and the weekly run share a ref and used to cancel one another. The acceptance mysql image is either the caller's databases input or the fixed mariadb:10.6 federated fallback; the ignore reason now says so. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Thomas Müller <323649642+oc-tmueller@users.noreply.github.com> --- .github/workflows/acceptance.yml | 2 +- .github/workflows/zizmor.yml | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/acceptance.yml b/.github/workflows/acceptance.yml index 0b8e887caaf..258b907bd04 100644 --- a/.github/workflows/acceptance.yml +++ b/.github/workflows/acceptance.yml @@ -90,7 +90,7 @@ jobs: services: mysql: - image: >- # zizmor: ignore[unpinned-images] the tag comes from the caller's databases input + image: >- # zizmor: ignore[unpinned-images] tags come from the caller's databases input, or the fixed mariadb:10.6 fallback ${{ case(startsWith(matrix.database,'mysql:') || startsWith(matrix.database,'mariadb:'), matrix.database, inputs.federated-folder != '', 'mariadb:10.6', '') }} env: MYSQL_ROOT_PASSWORD: password diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 938b3736841..7829c845742 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -18,9 +18,11 @@ on: permissions: contents: read +# Only pull request runs cancel each other: a push to the default branch and +# the weekly run share a ref, and neither should cancel the other. concurrency: group: zizmor-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: zizmor: