diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 00000000..a4360b1e --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,22 @@ +# Security Policy + +## Supported Versions + +The latest patch version of the `1.x` release series is supported for security updates. + +## Reporting a Vulnerability + +PHPCSExtra is a developer tool and should generally not be used in a production (web accessible) environment. + +Having said that, responsible disclosure of security issues is highly appreciated. + +**Please do not report or discuss security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Issues can be reported privately to the maintainers by opening a [Security vulnerability report](https://github.com/PHPCSStandards/PHPCSExtra/security/advisories/new). + +### Preferences + +* Please provide detailed reports with reproducible steps and a clearly defined impact. +* Include the version number of the vulnerable package in your report. +* Fixes are most welcome. + A private PR can be created from the security report to work on and discuss the patch. diff --git a/.github/release-checklist.md b/.github/release-checklist.md index b2e1f5f2..c684f9e7 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -21,7 +21,7 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] Close the milestone - [ ] Open a new milestone for the next release - [ ] If any open PRs/issues which were milestoned for this release did not make it into the release, update their milestone. -- [ ] Fast-forward `develop` to be equal to `master` +- [ ] Fast-forward `develop` to be equal to `stable` ### Publicize - [ ] Tweet about the release. diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index ede7f6ac..44b8614d 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -4,8 +4,6 @@ on: # Run on all pushes and on all pull requests. # Prevent the build from running when there are only irrelevant changes. push: - paths-ignore: - - '**.md' pull_request: # Allow manually triggering the workflow. workflow_dispatch: @@ -141,8 +139,8 @@ jobs: remark-lint-heading-whitespace remark-lint-list-item-punctuation remark-lint-match-punctuation + remark-lint-no-dead-urls remark-lint-no-hr-after-heading - remark-lint-are-links-valid-alive remark-lint-are-links-valid-duplicate remark-validate-links diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index bcb6c297..20c74c6b 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -76,9 +76,11 @@ jobs: composer-options: --ignore-platform-req=php+ custom-cache-suffix: $(date -u "+%Y-%m") - - name: "Composer: set PHPCS version for tests (lowest)" + - name: "Composer: set PHPCS/PHPCSUtils version for tests (lowest)" if: ${{ matrix.phpcs_version == 'lowest' }} - run: composer update squizlabs/php_codesniffer --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction + run: > + composer update squizlabs/php_codesniffer phpcsstandards/phpcsutils + --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cc83b771..aa2b3201 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -82,9 +82,11 @@ jobs: composer-options: --ignore-platform-req=php+ custom-cache-suffix: $(date -u "+%Y-%m") - - name: "Composer: set PHPCS version for tests (lowest)" + - name: "Composer: set PHPCS/PHPCSUtils version for tests (lowest)" if: ${{ matrix.phpcs_version == 'lowest' }} - run: composer update squizlabs/php_codesniffer --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction + run: > + composer update squizlabs/php_codesniffer phpcsstandards/phpcsutils + --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' @@ -153,9 +155,11 @@ jobs: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") - - name: "Composer: set PHPCS version for tests (lowest)" + - name: "Composer: set PHPCS/PHPCSUtils version for tests (lowest)" if: ${{ matrix.phpcs_version == 'lowest' }} - run: composer update squizlabs/php_codesniffer --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction + run: > + composer update squizlabs/php_codesniffer phpcsstandards/phpcsutils + --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' @@ -180,7 +184,7 @@ jobs: - name: Upload coverage results to Coveralls if: ${{ success() }} env: - COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }} COVERALLS_PARALLEL: true COVERALLS_FLAG_NAME: php-${{ matrix.php }}-phpcs-${{ matrix.phpcs_version }} run: php-coveralls -v -x build/logs/clover.xml @@ -195,5 +199,5 @@ jobs: - name: Coveralls Finished uses: coverallsapp/github-action@v2 with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ secrets.COVERALLS_TOKEN }} parallel-finished: true diff --git a/.remarkrc b/.remarkrc index 83ab108b..1d946443 100644 --- a/.remarkrc +++ b/.remarkrc @@ -8,6 +8,15 @@ ["remark-lint-linebreak-style", "unix"], ["remark-lint-link-title-style", "\""], ["remark-lint-ordered-list-marker-style", "."], + [ + "remark-lint-no-dead-urls", + { + "skipUrlPatterns": [ + "https://www.php.net/", + "^https?://github\\.com/PHPCSStandards/PHPCSExtra/compare/[0-9\\.]+?\\.{3}[0-9\\.]+" + ] + } + ], "remark-lint-no-duplicate-defined-urls", "remark-lint-no-duplicate-definitions", "remark-lint-no-empty-url", @@ -29,7 +38,6 @@ "remark-lint-list-item-punctuation", "remark-lint-match-punctuation", "remark-lint-no-hr-after-heading", - "remark-lint-are-links-valid-alive", "remark-lint-are-links-valid-duplicate", "remark-validate-links" ] diff --git a/CHANGELOG.md b/CHANGELOG.md index 25270a54..62e346e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,25 @@ This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses _Nothing yet._ +## [1.0.4] - 2023-06-18 + +### Changed + +#### Other + +* Composer: The minimum `PHPCSUtils` requirement has been updated to `^1.0.6` (was ^1.0.0). [#237] +* Various housekeeping. + +### Fixed + +#### Universal + +* `Universal.Constants.LowercaseClassResolutionKeyword`: prevent false positives for function calls to methods called `class`. [#226] + +[#226]: https://github.com/PHPCSStandards/PHPCSExtra/pull/226 +[#237]: https://github.com/PHPCSStandards/PHPCSExtra/pull/237 + + ## [1.0.3] - 2023-03-28 ### Changed @@ -319,7 +338,7 @@ The upgrade to PHPCSUtils 1.0.0-alpha4 took care of a number of bugs, which pote [#64]: https://github.com/PHPCSStandards/PHPCSExtra/pull/64 [#65]: https://github.com/PHPCSStandards/PHPCSExtra/pull/65 -[operator precedence]: https://www.php.net/manual/en/language.operators.precedence.php +[operator precedence]: https://www.php.net/language.operators.precedence ## [1.0.0-alpha2] - 2020-02-18 @@ -422,6 +441,7 @@ This initial alpha release contains the following sniffs: [php_version-config]: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Configuration-Options#setting-the-php-version [Unreleased]: https://github.com/PHPCSStandards/PHPCSExtra/compare/stable...HEAD +[1.0.4]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.3...1.0.4 [1.0.3]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.2...1.0.3 [1.0.2]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.1...1.0.2 [1.0.1]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0...1.0.1 diff --git a/README.md b/README.md index 068c7111..2120ce3d 100644 --- a/README.md +++ b/README.md @@ -337,7 +337,7 @@ Enforce that the names used in a class/enum "implements" statement or an interfa Enforce the use of the boolean `&&` and `||` operators instead of the logical `and`/`or` operators. -:information_source: Note: as the [operator precedence](https://www.php.net/manual/en/language.operators.precedence.php) of the logical operators is significantly lower than the operator precedence of boolean operators, this sniff does not contain an auto-fixer. +:information_source: Note: as the [operator precedence](https://www.php.net/language.operators.precedence) of the logical operators is significantly lower than the operator precedence of boolean operators, this sniff does not contain an auto-fixer. #### `Universal.Operators.DisallowShortTernary` :bar_chart: :books: diff --git a/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php b/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php index 692243bd..b5a3330a 100644 --- a/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php +++ b/Universal/Sniffs/Classes/ModifierKeywordOrderSniff.php @@ -12,7 +12,6 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; -use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\ObjectDeclarations; /** @@ -177,7 +176,7 @@ private function handleError(File $phpcsFile, $firstKeyword, $secondKeyword) $i = ($secondKeyword + 1); while ($tokens[$i]['code'] === \T_WHITESPACE) { $phpcsFile->fixer->replaceToken($i, ''); - $i++; + ++$i; } // Use the original token content as the case used for keywords is not the concern of this sniff. diff --git a/Universal/Sniffs/Constants/LowercaseClassResolutionKeywordSniff.php b/Universal/Sniffs/Constants/LowercaseClassResolutionKeywordSniff.php index d461dd2e..6df4e5fe 100644 --- a/Universal/Sniffs/Constants/LowercaseClassResolutionKeywordSniff.php +++ b/Universal/Sniffs/Constants/LowercaseClassResolutionKeywordSniff.php @@ -67,6 +67,12 @@ public function process(File $phpcsFile, $stackPtr) return; } + $nextToken = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($nextToken !== false && $tokens[$nextToken]['code'] === \T_OPEN_PARENTHESIS) { + // Function call or declaration for a function called "class". + return; + } + $prevToken = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($prevToken === false || $tokens[$prevToken]['code'] !== \T_DOUBLE_COLON) { return; diff --git a/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php b/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php index e779bd22..34cf28d8 100644 --- a/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php +++ b/Universal/Sniffs/Constants/ModifierKeywordOrderSniff.php @@ -187,7 +187,7 @@ private function handleError(File $phpcsFile, $firstKeyword, $secondKeyword) $i = ($secondKeyword + 1); while ($tokens[$i]['code'] === \T_WHITESPACE) { $phpcsFile->fixer->replaceToken($i, ''); - $i++; + ++$i; } // Use the original token content as the case used for keywords is not the concern of this sniff. diff --git a/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php b/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php index d91ea3d3..2deee1a8 100644 --- a/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php +++ b/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php @@ -94,7 +94,7 @@ public function process(File $phpcsFile, $stackPtr) $this->tabWidth = Helper::getTabWidth($phpcsFile); } - if (defined('PHP_CODESNIFFER_IN_TESTS')) { + if (\defined('PHP_CODESNIFFER_IN_TESTS')) { $this->tabWidth = Helper::getCommandLineData($phpcsFile, 'tabWidth'); } diff --git a/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc b/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc index 0d2c714c..2f598c0b 100644 --- a/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc +++ b/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc @@ -27,3 +27,12 @@ namespace MyNameSpace { echo bar::CLASS; array_map([\MyNameSpace\xyz :: /* comment */ Class, 'methodName'], $array); + +// Safeguard against false positives for methods called "class". +class NotTheMagicConstant { + public function &Class() { + self::Class(); + NotTheMagicConstant::CLASS(); + My\Class\ClassName::clASS(); + } +} diff --git a/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc.fixed b/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc.fixed index fbac4026..fdda1eda 100644 --- a/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc.fixed +++ b/Universal/Tests/Constants/LowercaseClassResolutionKeywordUnitTest.inc.fixed @@ -27,3 +27,12 @@ namespace MyNameSpace { echo bar::class; array_map([\MyNameSpace\xyz :: /* comment */ class, 'methodName'], $array); + +// Safeguard against false positives for methods called "class". +class NotTheMagicConstant { + public function &Class() { + self::Class(); + NotTheMagicConstant::CLASS(); + My\Class\ClassName::clASS(); + } +} diff --git a/composer.json b/composer.json index 6a8cb018..9e56a009 100644 --- a/composer.json +++ b/composer.json @@ -22,13 +22,13 @@ "require" : { "php" : ">=5.4", "squizlabs/php_codesniffer" : "^3.7.1", - "phpcsstandards/phpcsutils" : "^1.0" + "phpcsstandards/phpcsutils" : "^1.0.6" }, "require-dev" : { "php-parallel-lint/php-parallel-lint": "^1.3.2", "php-parallel-lint/php-console-highlighter": "^1.0", - "phpcsstandards/phpcsdevcs": "^1.1.5", - "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevtools": "^1.2.1", "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0" }, "extra": {