diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-03 22:18:32 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-03 22:18:32 +0900 |
| commit | 55e6f5367bf86d1dc6e99b7492d86c5208dd1f1c (patch) | |
| tree | f923e44b120790aa1244f5183aba4f908754029b | |
| parent | 9a467625ff8d135c650c7fefacfa0358002ce4d2 (diff) | |
| download | php-mozart-55e6f5367bf86d1dc6e99b7492d86c5208dd1f1c.tar.gz php-mozart-55e6f5367bf86d1dc6e99b7492d86c5208dd1f1c.tar.zst php-mozart-55e6f5367bf86d1dc6e99b7492d86c5208dd1f1c.zip | |
fix(resolver): reject partial update when locked version fails stability
A partial update reuses every non-allow-listed locked package as a
fixed pool entry, ignoring stability filters. So when a user tightens
`minimum-stability` (or drops a `stability-flags` entry the lock used
to ride on), Mozart silently kept the rejected version and produced a
plan Composer would have failed on. Mirror Composer's
`Pool::isUnacceptableFixedOrLockedPackage` path: walk the locked
packages before pool construction, surface every entry whose version
no longer passes `passes_stability_filter`, and bail with the same
"fixed to <v> (lock file version) ... rejected by your
minimum-stability" pointer Composer prints from
`Problem::getPrettyString`.
| -rw-r--r-- | crates/mozart-registry/src/resolver.rs | 38 | ||||
| -rw-r--r-- | crates/mozart/tests/installer.rs | 2 |
2 files changed, 39 insertions, 1 deletions
diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs index 33c3659..67650e6 100644 --- a/crates/mozart-registry/src/resolver.rs +++ b/crates/mozart-registry/src/resolver.rs @@ -1010,6 +1010,44 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R // different version (whether directly, or via `replace`, which would // otherwise let an upgraded replacer silently drop the dependency). // + // Pre-check: a locked package whose version is rejected by the + // current minimum-stability (composer.json may have tightened + // stability or dropped a `stability-flags` entry the lock relied on) + // cannot be reused as a fixed pool entry. Mirrors what Composer + // surfaces via `Pool::isUnacceptableFixedOrLockedPackage` + + // `Problem::getPrettyString`: bail with the "fixed to <v> (lock file + // version) but that version is rejected by your minimum-stability" + // pointer so the user knows to add the package to the update + // arguments (or use `--with-all-dependencies`). + { + let mut rejected: Vec<String> = Vec::new(); + for locked in &request.locked_packages { + let Ok(v) = Version::parse(&locked.version_normalized) else { + continue; + }; + if !passes_stability_filter( + &locked.name, + &v, + request.minimum_stability, + &stability_flags, + ) { + rejected.push(format!( + " - {} is fixed to {} (lock file version) by a partial update but that version is rejected by your minimum-stability. Make sure you list it as an argument for the update command.", + locked.name, locked.pretty_version + )); + } + } + if !rejected.is_empty() { + let report = rejected + .into_iter() + .enumerate() + .map(|(i, msg)| format!(" Problem {}\n{}", i + 1, msg)) + .collect::<Vec<_>>() + .join("\n"); + return Err(ResolveError::NoSolution(report)); + } + } + // Build a map first so the filter below knows which (name, version) // pairs are the only allowed entries for locked names. let locked_name_to_version: IndexMap<String, String> = request diff --git a/crates/mozart/tests/installer.rs b/crates/mozart/tests/installer.rs index 5133167..5e285a9 100644 --- a/crates/mozart/tests/installer.rs +++ b/crates/mozart/tests/installer.rs @@ -282,7 +282,7 @@ installer_fixture!(load_replaced_package_if_replacer_dropped); installer_fixture!(outdated_lock_file_fails_install); installer_fixture!(outdated_lock_file_with_new_platform_reqs_fails); installer_fixture!(partial_update_always_updates_symlinked_path_repos, ignore); -installer_fixture!(partial_update_downgrades_non_allow_listed_unstable, ignore); +installer_fixture!(partial_update_downgrades_non_allow_listed_unstable); installer_fixture!( partial_update_forces_dev_reference_from_lock_for_non_updated_packages, ignore |
