From beef412a85d35c39b58793fa4a3c5a4d53efb2f7 Mon Sep 17 00:00:00 2001 From: Matthew J Mucklo Date: Sun, 19 Apr 2026 23:22:53 -0700 Subject: [PATCH] Add Psalm cross-check alongside PHPStan Psalm level 3 with a 66-entry baseline. All findings are either false positives (PossiblyUnusedMethod for public API methods Psalm can't see callers for), duplicates of existing PHPStan baseline entries (TypeDoesNotContainType, RedundantCondition for state-machine tautologies), or already-handled edge cases (mb_regex_encoding return type). Found no genuinely new bugs that PHPStan level 8 missed. Value is as a cross-check: new code that triggers a Psalm error outside the baseline will surface during review even if PHPStan doesn't flag it. Also dismisses Dependabot alert #1 (PHPUnit GHSA-qrr6-mg7r-m243) as tolerable risk: dev-only dependency, vulnerability requires process isolation mode which we don't use, fix requires PHP 8.3+ which would drop our 8.1/8.2 support, no backport to PHPUnit 9.x. New: composer psalm script, psalm.xml config, psalm-baseline.xml. ROADMAP: Psalm item flipped to [x]. --- .github/workflows/ci.yml | 24 ++++++++- .scrutinizer.yml | 5 ++ ROADMAP.md | 2 +- composer.json | 4 +- psalm-baseline.xml | 105 +++++++++++++++++++++++++++++++++++++++ psalm.xml | 18 +++++++ 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 psalm-baseline.xml create mode 100644 psalm.xml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9930a50..7fa29e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,4 +119,26 @@ jobs: run: composer install --prefer-dist --no-progress --no-suggest - name: Run PHPStan - run: bin/phpstan analyse --error-format=github + run: bin/phpstan analyse --memory-limit=512M --error-format=github + + psalm: + name: Static Analysis (Psalm) + runs-on: ubuntu-latest + continue-on-error: true + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + extensions: mbstring, intl + coverage: none + + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run Psalm + run: bin/psalm --memory-limit=512M --output-format=github diff --git a/.scrutinizer.yml b/.scrutinizer.yml index 53d3598..c778e4d 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -14,6 +14,11 @@ checks: build: image: default-jammy + environment: + php: 8.2 + dependencies: + override: + - composer install --no-interaction --no-scripts --ignore-platform-reqs nodes: analysis: tests: diff --git a/ROADMAP.md b/ROADMAP.md index 32fdc16..9f71d56 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -88,7 +88,7 @@ Not tied to a specific release; picked up as time allows. **Static analysis:** - [x] PHPStan level 6 → 8 — tighter generics and inference; required four small nullable-return guards (`idn_to_ascii`, `mb_split`, `file_get_contents`) and one local docblock shape on `parseMultiple()`. -- [ ] Add Psalm alongside PHPStan for cross-tool coverage; keep both green. +- [x] Psalm alongside PHPStan — level 3 with baseline (66 entries, all false positives or duplicates of PHPStan findings). Found no genuinely new bugs vs PHPStan level 8; serves as a cross-check for future regressions. `composer psalm`. **Performance:** - [x] PhpBench suite — `benchmarks/ParseBench.php` covers single ASCII, name-addr, UTF-8 local-part, IDN, obs-route, 10-address comma batch, 100-address `parseStream` batch, invalid inputs, and comment extraction. Run with `composer bench`. diff --git a/composer.json b/composer.json index 68d035d..58b7380 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,8 @@ "phpunit/phpunit": "^9.6", "symfony/yaml": "^6.4|^7.2", "infection/infection": "^0.29.8", - "phpbench/phpbench": "^1.4" + "phpbench/phpbench": "^1.4", + "vimeo/psalm": "^6.0" }, "require": { "php": "^8.1", @@ -59,6 +60,7 @@ "cs:check": "php-cs-fixer fix --dry-run --diff", "cs:fix": "php-cs-fixer fix", "stan": "phpstan analyse --memory-limit=512M", + "psalm": "psalm --memory-limit=512M", "infect": "XDEBUG_MODE=coverage infection --threads=max", "bench": "phpbench run --report=default", "ci": [ diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 0000000..7c3ea55 --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..9ca84db --- /dev/null +++ b/psalm.xml @@ -0,0 +1,18 @@ + + + + + + + + +