Verification Metadata
- Route:
/transparency/php-packages/ - Last verified:
- Next review due:
- Verification scope: Composer runtime and dev-time direct dependencies, transitive dependency graph, CVE status, and replacement decisions.
- Previous version: PHP Package Dependency Transparency before the June 2026 tooling update
Our Dependency Philosophy
PayCal's position on third-party dependencies is: use the minimum possible, own what is practical to own, and pin everything else. This is not a reaction to a specific incident — it is the standing default.
- Every package must justify its existence by active call sites. A zero-reference dependency is removed regardless of CVE status.
- When a package is only used at one or two narrow call sites, we evaluate whether a first-party implementation is practical. Fewer moving parts means a smaller attack surface.
- All packages are pinned in composer.lock. No floating versions. No silent upgrades.
- Transitive dependencies are reviewed as a side effect of direct dependency audits. Orphaned vendor directories are removed.
Runtime Dependencies
These are the only PHP packages loaded in a production request. Each is justified by active usage and has no alternative that would reduce the dependency further without significant first-party engineering effort.
| Package | Version | Purpose | Transitive packages pulled in |
|---|---|---|---|
lbuchs/webauthn |
2.2.0 | Passkey and FIDO2 registration and authentication for passwordless sign-in. | 0 |
phpoffice/phpspreadsheet |
5.7.0 | XLSX generation for earnings export downloads. | ~9 (maennchen/zipstream-php, markbaker/complex, markbaker/matrix, myclabs/deep-copy, psr/simple-cache, symfony/polyfill-*) |
stripe/stripe-php |
20.1.0 | Stripe billing API: subscription management, webhook verification, customer and payment intent operations. | 0 |
Development-Only Dependencies
Dev-time dependencies are never loaded in production. The following packages are used exclusively during development and CI.
| Package | Version | Purpose | Transitive packages pulled in |
|---|---|---|---|
phpstan/phpstan |
2.1.54 | Static analysis at Level 9. Enforced in pre-push hook and CI. No baseline file permitted. | ~8 (nikic/php-parser, react/*, clue/ndjson-react, fidry/cpu-core-counter, etc.) |
phpunit/phpunit |
13.1.8 | Unit and integration test runner. 1,527 tests across Domain, Controllers, Infrastructure, and Observability layers. | ~15 (sebastian/*, phpunit/php-*, phar-io/*, myclabs/deep-copy, etc.) |
friendsofphp/php-cs-fixer |
3.95.1 | Code style enforcement. Dry-run check runs on every staged PHP file in the pre-commit hook and in CI. | ~12 (symfony/console, symfony/finder, symfony/event-dispatcher, ergebnis/agent-detector, etc.) |
CVE Review and the 2026-05 Audit
Periodically GitHub Dependabot alerts flag packages as vulnerable. Before removing or replacing a package, PayCal verifies the specific CVE status at the installed version using the upstream advisory and the Packagist security database. During the 2026-05 audit, four moderate Dependabot alerts were raised. Investigation confirmed all four were already patched at the installed versions — no remediation action was required.
Separately, two packages — erusev/parsedown and yupmin/magoo — were found to have no usage anywhere in the codebase. They were removed regardless of CVE status. A package that is not loaded is a package that cannot be exploited.
Why We Replaced vlucas/phpdotenv
PayCal previously loaded .env files using vlucas/phpdotenv, a widely-used library with three transitive dependencies (phpoption, graham-campbell/result-type). The library was used at exactly two call sites: one safeLoad in the bootstrap file, and one load in config.php.
Rather than maintain an external dependency for 11 lines of active usage, we wrote PayCal\Infrastructure\Env\Dotenv — a 140-line first-party class that covers the full surface we actually use: KEY=VALUE parsing, blank and comment skipping, optional quote stripping, inline comment stripping, immutable mode, and a forceKeys override for specific keys (which eliminated a separate 20-line manual workaround that had existed in config.php for the SMTP password).
The replacement removed 63 vendor files and three packages from the dependency graph. The public source for PayCal\Infrastructure\Env\Dotenv is available in the public repository.
CI/CD Controls
Every change must pass PHPStan Level 9 and the full PHPUnit test suite before it can be merged. Composer is locked to a deterministic dependency graph — no floating versions in production.
For the broader CI/CD operating model beyond PHP packages, see CI/CD Tooling and Release Governance.
.github/workflows/phpstan.yml: PHPStan Level 9 on PHP 8.4 and 8.5, includesformat:check..github/workflows/phpunit.yml: fast gate (PHP 8.4) → full validation (PHP 8.5) → deep verification (scheduled).- Pre-commit hook: PHPStan baseline check, AST snapshot, quick tests (1,055 tests).
- Pre-push hook: full PHPStan Level 9 + quick tests.
composer audit --lockedadvisory check.
How to Verify
# List all direct dependencies composer show --direct # Check for known security advisories composer audit --locked # Review the full dependency graph composer show # Inspect first-party .env loader (replaced vlucas/phpdotenv) cat html/src/Infrastructure/Env/Dotenv.php
Related transparency pages: CI/CD Tooling and Release Governance, Dependency and CI/CD Governance, and Framework and Backend Change Ledger.