From 757536ead68d7e2a17ea2a108f21dc72648f98c2 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 2 Jan 2025 15:09:58 +0100 Subject: [PATCH 1/3] ci(phpstan): Test PHPStan Signed-off-by: Joas Schilling --- .github/workflows/phpstan.yml | 46 ++++++++++++++++++ composer.json | 1 + phpstan.neon | 12 +++++ vendor-bin/phpstan/composer.json | 10 ++++ vendor-bin/phpstan/composer.lock | 80 ++++++++++++++++++++++++++++++++ 5 files changed, 149 insertions(+) create mode 100644 .github/workflows/phpstan.yml create mode 100644 phpstan.neon create mode 100644 vendor-bin/phpstan/composer.json create mode 100644 vendor-bin/phpstan/composer.lock diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 00000000..13f6e784 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,46 @@ +# This workflow is provided via the organization template repository +# +# https://github.com/nextcloud/.github +# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization +# +# SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: MIT + +name: PHPStan + +on: pull_request + +concurrency: + group: phpstan-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + phpstan-static-analysis: + runs-on: ubuntu-latest + + name: static-phpstan-analysis + steps: + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Get php version + id: versions + uses: icewind1991/nextcloud-version-matrix@58becf3b4bb6dc6cef677b15e2fd8e7d48c0908f # v1.3.1 + + - name: Set up php${{ steps.versions.outputs.php-available }} + uses: shivammathur/setup-php@c541c155eee45413f5b09a52248675b1a2575231 # v2.31.1 + with: + php-version: ${{ steps.versions.outputs.php-available }} + extensions: bz2, ctype, curl, dom, fileinfo, gd, iconv, intl, json, libxml, mbstring, openssl, pcntl, posix, session, simplexml, xmlreader, xmlwriter, zip, zlib, sqlite, pdo_sqlite + coverage: none + ini-file: development + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install dependencies + run: composer i + + - name: Run static analysis + run: composer run phpstan diff --git a/composer.json b/composer.json index 8a00c606..e44269cc 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,7 @@ "cs:check": "php-cs-fixer fix --dry-run --diff", "cs:fix": "php-cs-fixer fix", "openapi": "generate-spec", + "phpstan": "vendor/bin/phpstan analyse -c phpstan.neon", "psalm": "psalm --no-cache --threads=$(nproc)", "psalm:dev": "@psalm", "psalm:update-baseline": "psalm --threads=1 --update-baseline", diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000..9ff15dc7 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later +parameters: + level: 5 + paths: + - lib + scanFiles: + - tests/stub.phpstub + scanDirectories: + - vendor/nextcloud/ocp + ignoreErrors: + - '#on an unknown class Doctrine\\DBAL\\Schema\\Table#' diff --git a/vendor-bin/phpstan/composer.json b/vendor-bin/phpstan/composer.json new file mode 100644 index 00000000..cca14804 --- /dev/null +++ b/vendor-bin/phpstan/composer.json @@ -0,0 +1,10 @@ +{ + "config": { + "platform": { + "php": "8.1" + } + }, + "require-dev": { + "phpstan/phpstan": "^2.1.0" + } +} diff --git a/vendor-bin/phpstan/composer.lock b/vendor-bin/phpstan/composer.lock new file mode 100644 index 00000000..7c4a3c74 --- /dev/null +++ b/vendor-bin/phpstan/composer.lock @@ -0,0 +1,80 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "388bf2fccfe3fdc7c3d1d37409eba74a", + "packages": [], + "packages-dev": [ + { + "name": "phpstan/phpstan", + "version": "2.1.17", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053", + "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-05-21T20:55:28+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "platform-overrides": { + "php": "8.1" + }, + "plugin-api-version": "2.6.0" +} From 6b479e10645daad2ec0e295ebdc48994723f7457 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 2 Jan 2025 15:11:50 +0100 Subject: [PATCH 2/3] fix: Fix always true condition Signed-off-by: Joas Schilling --- lib/BackgroundJob/RetentionJob.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/BackgroundJob/RetentionJob.php b/lib/BackgroundJob/RetentionJob.php index 0ed81725..e94c3b46 100644 --- a/lib/BackgroundJob/RetentionJob.php +++ b/lib/BackgroundJob/RetentionJob.php @@ -103,7 +103,7 @@ public function run($argument): void { $offset = ''; $limit = 1000; - while ($offset !== null) { + while (true) { $fileIds = $this->tagMapper->getObjectIdsForTags((string)$tag, 'files', $limit, $offset); $this->logger->debug('Checking retention for ' . count($fileIds) . ' files in this chunk'); From 90a58f7eed2ed8e296883beb0e42acac513eb827 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 5 Feb 2026 14:04:36 +0100 Subject: [PATCH 3/3] fix(api): Offload integer validation to the server dispatcher Signed-off-by: Joas Schilling --- lib/Controller/APIController.php | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/lib/Controller/APIController.php b/lib/Controller/APIController.php index e2efa994..961ad226 100644 --- a/lib/Controller/APIController.php +++ b/lib/Controller/APIController.php @@ -86,10 +86,10 @@ public function getRetentions(): DataResponse { * Create a retention rule * * @param int $tagid Tag the retention is based on - * @param 0|1|2|3 $timeunit Time unit of the retention (days, weeks, months, years) + * @param int<0, 3> $timeunit Time unit of the retention (days, weeks, months, years) * @psalm-param Constants::UNIT_* $timeunit * @param positive-int $timeamount Amount of time units that have to be passed - * @param 0|1 $timeafter Whether retention time is based creation time (0) or modification time (1) + * @param int<0, 1> $timeafter Whether retention time is based creation time (0) or modification time (1) * @psalm-param Constants::MODE_* $timeafter * @return DataResponse|DataResponse * @@ -103,16 +103,6 @@ public function addRetention(int $tagid, int $timeunit, int $timeamount, int $ti return new DataResponse(['error' => 'tagid'], Http::STATUS_BAD_REQUEST); } - if ($timeunit < 0 || $timeunit > 3) { - return new DataResponse(['error' => 'timeunit'], Http::STATUS_BAD_REQUEST); - } - if ($timeamount < 1) { - return new DataResponse(['error' => 'timeamount'], Http::STATUS_BAD_REQUEST); - } - if ($timeafter < 0 || $timeafter > 1) { - return new DataResponse(['error' => 'timeafter'], Http::STATUS_BAD_REQUEST); - } - $qb = $this->db->getQueryBuilder(); $qb->insert('retention') ->setValue('tag_id', $qb->createNamedParameter($tagid)) @@ -140,7 +130,7 @@ public function addRetention(int $tagid, int $timeunit, int $timeamount, int $ti * Delete a retention rule * * @param int $id Retention rule to delete - * @return DataResponse, array{}> + * @return DataResponse * * 204: Retention rule deleted * 404: Retention rule not found