lockrot¶
Finds abandoned, unmaintained and branch-pinned packages in composer.lock — and releases that
promise a PHP version they were never tested against.
Install¶
composer require --dev somework/lockrot
composer config allow-plugins.somework/lockrot true
composer lockrot --target-php=8.4
Adds one dev dependency and one command. It also prints a short summary during
composer require, update and install, above the operations list — see
Install-time summary.
Nothing is added to your project. For the checksum-verified download and how
self-update works, see PHAR and self-update.
composer global update keeps it current. Because it is a plugin rather than a
PHAR, the install-time summary then runs in every project you touch;
Install-time summary explains how to turn that off.
Requires PHP 7.4 or newer and Composer 2.2 or newer.
What a run looks like¶
critical (3) abandoned sensio/framework-extra-bundle v6.2.10 direct marked abandoned by its repository, replacement: Symfony; last release 2023-02-24 (3.6 years ago); repository archived on GitHub; last push 2023-02-24 (3.6 years ago); released 2023-02-24, before PHP 8.4 GA (2024-11-21); php constraint ">=7.2.5" has no upper bound silent javibravo/simpleue 2.1.0 direct last release 2017-11-15 (8.8 years ago); last push 2017-11-18 (8.8 years ago); released 2017-11-15, before PHP 8.4 GA (2024-11-21); php constraint ">=5.5" has no upper bound silent mnapoli/piwik-twig-extension 3.0.0 direct last release 2020-04-24 (6.4 years ago); last push 2020-04-28 (6.4 years ago); released 2020-04-24, before PHP 8.4 GA (2024-11-21); php constraint ">=7.0" has no upper bound high (58) abandoned behat/transliterator v1.5.0 via stof/doctrine-extensions-bundle › gedmo/doctrine-extensions marked abandoned by its repository; last release 2022-03-30 (4.5 years ago); repository archived on GitHub; released 2022-03-30, before PHP 8.4 GA (2024-11-21); php constraint ">=7.2" has no upper bound
The first 21 lines of a real run against wallabag's 200-package lock file, at 100 columns. Four of its 74 findings — read the whole report.
What it looks for¶
abandoned— the package's own repository says so: Packagist carries theabandonedmarker a maintainer set by hand, or GitHub shows the repository archived.silent— five years with no stable release and five years with no push to the repository, on the default thresholds. Nobody announced anything; the package simply stopped.pinned— your lock file holds a branch snapshot or a commit hash instead of a released version, so the thing you installed has no version number anyone else can ask for.old-promise— the release predates the PHP version you target, and itsrequire.phpconstraint is open-ended, so Composer accepted it on a PHP nobody released it against.
A fifth verdict, stale, catches a package that is old on one of those fronts but not both — worth
knowing, rarely worth acting on. Every finding carries the evidence behind it, the date the data was
read, and the chain of requirements that pulled the package in.
What it reports has all eight verdicts and the priority rules.
"Composer already warns me about abandoned packages"¶
It does, and lockrot reports the same thing. composer audit --abandoned reads one field: the
abandoned marker a maintainer sets by hand on Packagist. Most packages that stop being maintained
never get it, because setting it is the last act of someone who has already walked away — so the
field is accurate when it is there, and silent the rest of the time.
lockrot reads that field too, and then keeps going. It asks when the last stable release actually
landed, when the repository was last pushed to, whether your lock file is holding a branch snapshot
rather than a version, and whether a release made an open-ended PHP promise it was never tested
against. It reads composer.lock and composer.json, and it writes to neither.
In CI¶
Nothing fails a build until you ask it to: fail-on is none by default, exit 1 means a finding
reached the threshold you chose, and exit 2 is reserved for lockrot's own errors. Recipes for
GitHub Actions, GitLab CI and PR comments are in In CI; a
baseline lets you accept what you have today and fail only on what arrives tomorrow.
Read on¶
| Page | What is on it |
|---|---|
| What it reports | The eight verdicts, the signals behind them, and how priority is assigned |
| Configuration | extra.lockrot, every option, and the command-line flags |
| In CI | GitHub Actions, GitLab CI, SARIF, PR comments |
| Baseline | Accept today's findings, fail on new and worsened ones |
| Install-time summary | What the plugin prints during install/update, and how to silence it |
| PHAR and self-update | Verified download, self-update, the global-plugin alternative |
| Example run | The full 200-package report the sample above is cut from |
| How it fetches metadata | Composer repositories, the GitHub API, caching, --offline |
| Changelog | What changed, release by release |
Source and issues live on GitHub; the package is
somework/lockrot on Packagist. Released under
the MIT licence.