News

Cooldown Dependency Policy now in Composer 2.11

Published
Cooldown Dependency Policy now in Composer 2.11 image

Composer 2.11.0 has a new cooldown dependency policy. You set a waiting time, such as one day, and Composer skips any package version published more recently than that. Composer 2.10 added the first dependency policies, which block versions with security advisories or known malware.

This release also includes six security fixes and faster dependency resolution. If you still depend on Composer falling back to source installs, check the upgrade notes first, since that behavior is gone.

What's New

Cooldown Dependency Policy

Say you set a one-day cooldown, and someone publishes a malicious version of a package you depend on. Composer won't install that version for a day after it was published. If the version is reported and removed in that time, your project never installs it. The policy is off until you set a period under config.policy:

{
    "config": {
        "policy": {
            "cooldown": {
                "period": "1 day"
            }
        }
    }
}

The period takes a string such as "6 hours" or "7 days", using the units second, minute, hour, day, or week. It also accepts an integer number of seconds.

The policy applies when Composer resolves dependencies during composer update and composer require. The require, init, and create-project commands skip withheld versions when they pick a version constraint. composer outdated and composer show --latest report the newest version you are allowed to install and mark newer releases that are still in the cooldown period.

The cooldown does not affect composer install, which installs exactly what is in composer.lock. Dev versions such as dev-main and platform packages (PHP and extensions) are never withheld.

composer update vendor/package leaves every other locked package alone. A full composer update re-evaluates everything, and it replaces a locked version still in the cooldown period with an older release. If no older version satisfies your constraints, the update fails.

You can exempt packages with an ignore list. Entries support reasons, version constraints, and wildcards:

{
    "config": {
        "policy": {
            "cooldown": {
                "period": "1 day",
                "ignore": {
                    "mycompany/*": "We trust the code in our own packages"
                }
            }
        }
    }
}

When you need a security fix right away, pass --no-cooldown to update, require, remove, or create-project. This skips only the cooldown. The advisory, malware, and custom policies still apply.

composer update --no-cooldown vendor/package

In CI, you can set or override the period with the COMPOSER_POLICY_COOLDOWN_PERIOD environment variable. Setting it to 0 turns off the cooldown for that run.

Composer 2.10 shipped without this policy because the only timestamp in package metadata was the time field, which package authors control. Packagist.org now reports a published-time for each version, based on when Packagist first made that version available. If a different Composer repository does not report published-time for a version Composer needs, the command fails and names the package. For repositories you trust, set require-published-time to false to fall back to the time field in each package's composer.json. VCS, path, and artifact repositories always use time.

Private Packagist already supports the cooldown policy. Organization admins can also set one cooldown period for every project in the organization, regardless of which Composer version each project uses.

If you used the community Heimdall plugin to set a minimum package age, Composer can now do this without a plugin.

PRs: #12692, #13098, #13099, #13100, #13102, #13153

Security Fixes

  • GHSA-c968-33g3-wh7p: during install or reinstall, Composer no longer writes files outside the vendor directory when a package name in vendor/composer/installed.json points there.
  • GHSA-fm2w-xgf2-f9fh: HTTP headers set on inline repositories, such as API tokens, are no longer written to composer.lock or installed.json.
  • TLS connections that use the distrusted eMudhra intermediate certificates are rejected, even when the system CA store trusts their roots (#13146).
  • Bin proxies now escape package-controlled paths and shebangs, and Composer rejects paths that contain shell metacharacters (#13056).
  • The secure-http setting also catches invalid URLs and git's <transport>::<address> syntax (#13144).
  • Repository options such as custom headers are no longer sent to dist URLs on hosts whose names only start with the repository's host name (#13142).

Custom Policy Block Scope

Custom dependency policies used to block versions only during composer update. You can now set block-scope on a custom policy to install or all to have it block during composer install as well. The default is update:

{
    "config": {
        "policy": {
            "my-policy": {
                "block-scope": "all"
            }
        }
    }
}

Say your policy starts blocking a version that is already in your committed lock file. With block-scope set to all, the next composer install in CI or on deploy fails instead of installing that version.

PR: #12990

Source Fallback Removed

Composer usually installs a package from its dist, a zip archive of the release. If that download fails, Composer no longer falls back to cloning the package's source repository. The temporary source-fallback option, deprecated in 2.10, is also gone. You can still install from source with the preferred-install config option (which can be set per vendor) or the --prefer-source flag.

PR: #13050

Faster Dependency Resolution

Composer now resolves dependencies faster and with less memory. The announcement doesn't include benchmarks, but #13174 measured one of the changes on laravel/laravel: CPU time for composer update --no-install dropped from 1.50 seconds to 1.18 seconds.

PRs: #13071, #13072, #13103, #13123, #13124, #13132, #13174

Other Improvements

  • composer audit --direct (-D) audits only your direct dependencies (#13121)
  • outdated and show --latest load package metadata in parallel (#13113)
  • Composer no longer requests HTTP/3, which caused a delay on new connections with recent curl versions (#13096)
  • Requests that return HTTP 429 with a Retry-After header are retried (#13082)
  • composer install fails when composer.lock has a merge conflict in its content-hash (#13105)
  • Conflict error messages now say when a version was blocked by a security advisory (#13108, #13075)
  • VCS repositories accept an only-branches option (#13086)
  • strict-psr-autoloader is now a config option (#12893)
  • Support for ssh.bitbucket.org (#13152)
  • Terminal progress reporting through OSC 7501 and OSC 9 sequences, configurable with COMPOSER_TERMINAL_STATUS (#13117)

Upgrade Notes

Upgrade with:

composer self-update
  • If a package only installs correctly from source, set preferred-install to source for that package, or pass --prefer-source.
  • Changes to the policy config now mark the lock file as outdated. Projects that have a policy config will see a warning after upgrading until they update the lock file (#13149).

References

Yannick Lyn Fatt photo

Staff Writer at Laravel News and Full stack web developer.

Sponsored

serpapi logo
SerpApi

The Web Search API for Your LLM and AI Applications

Visit SerpApi

The latest

View all →
Live Props for Real-Time Updates in Inertia.js v3.11 image

Live Props for Real-Time Updates in Inertia.js v3.11

Read article
Email Sending and Testing for Laravel in One Account image

Email Sending and Testing for Laravel in One Account

Read article
Decide with Jev: Tie Every AI Check to the Exact Draft image

Decide with Jev: Tie Every AI Check to the Exact Draft

Read article
PIE 1.5 Changes PHP Extension Installs in CI image

PIE 1.5 Changes PHP Extension Installs in CI

Read article
Delete Expired Sessions in Laravel With a Scheduled Command image

Delete Expired Sessions in Laravel With a Scheduled Command

Read article
Pollora: Run WordPress Inside a Laravel Application image

Pollora: Run WordPress Inside a Laravel Application

Read article