aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src/commands
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-03 22:47:33 +0900
committernsfisis <nsfisis@gmail.com>2026-05-03 22:47:33 +0900
commit2b48ae7bcf857bc35de95968513750c2d6e6de7b (patch)
tree3b76b3e3b673c5f4e8fbd20775e35d062e73b1f7 /crates/mozart/src/commands
parentcccdce42f6eb5c21179bf7b2fbd482a7d29c3b9d (diff)
downloadphp-mozart-2b48ae7bcf857bc35de95968513750c2d6e6de7b.tar.gz
php-mozart-2b48ae7bcf857bc35de95968513750c2d6e6de7b.tar.zst
php-mozart-2b48ae7bcf857bc35de95968513750c2d6e6de7b.zip
fix(resolver): honor config.audit.block-insecure security-advisory filter
Mozart silently ignored the `security-advisories` block on inline `type: package` repositories and the `config.audit.block-insecure` audit flag, so a `composer update` succeeded with packages a Composer run would have refused to load. Mirror Composer's `SecurityAdvisoryPoolFilter` for the slice that feeds the pool: - Plumb a `security-advisories` field through `RawRepository` and a `block_insecure` flag through `ResolveRequest`, lifted off `composer.json`'s `config.audit.block-insecure`. - Collect every advisory's `affectedVersions` constraint at resolve time. When `block_insecure` is set and an inline package's normalized version satisfies the constraint, drop it from the pool before solving — root requires with no unaffected candidate then fail with the standard "could not be resolved" error.
Diffstat (limited to 'crates/mozart/src/commands')
-rw-r--r--crates/mozart/src/commands/create_project.rs1
-rw-r--r--crates/mozart/src/commands/init.rs2
-rw-r--r--crates/mozart/src/commands/remove.rs4
-rw-r--r--crates/mozart/src/commands/require.rs3
-rw-r--r--crates/mozart/src/commands/update.rs20
5 files changed, 26 insertions, 4 deletions
diff --git a/crates/mozart/src/commands/create_project.rs b/crates/mozart/src/commands/create_project.rs
index a7964ae..61cb886 100644
--- a/crates/mozart/src/commands/create_project.rs
+++ b/crates/mozart/src/commands/create_project.rs
@@ -445,6 +445,7 @@ pub async fn execute(
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
console.info("Resolving dependencies...");
diff --git a/crates/mozart/src/commands/init.rs b/crates/mozart/src/commands/init.rs
index 1a6df37..209be4b 100644
--- a/crates/mozart/src/commands/init.rs
+++ b/crates/mozart/src/commands/init.rs
@@ -707,6 +707,7 @@ fn parse_repositories(repos: &[String]) -> anyhow::Result<Vec<RawRepository>> {
only: None,
exclude: None,
canonical: None,
+ security_advisories: None,
});
} else {
// Plain URL
@@ -717,6 +718,7 @@ fn parse_repositories(repos: &[String]) -> anyhow::Result<Vec<RawRepository>> {
only: None,
exclude: None,
canonical: None,
+ security_advisories: None,
});
}
}
diff --git a/crates/mozart/src/commands/remove.rs b/crates/mozart/src/commands/remove.rs
index c52d410..d4b3aef 100644
--- a/crates/mozart/src/commands/remove.rs
+++ b/crates/mozart/src/commands/remove.rs
@@ -279,6 +279,7 @@ pub async fn execute(
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
// Print header messages
@@ -567,6 +568,7 @@ async fn remove_unused(
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
console.info("Resolving dependencies to detect unused packages...");
@@ -925,6 +927,7 @@ mod tests {
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
let resolved = resolve(&request)
.await
@@ -986,6 +989,7 @@ mod tests {
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
let resolved2 = resolve(&request2)
.await
diff --git a/crates/mozart/src/commands/require.rs b/crates/mozart/src/commands/require.rs
index 3ff5ced..b302ed9 100644
--- a/crates/mozart/src/commands/require.rs
+++ b/crates/mozart/src/commands/require.rs
@@ -667,6 +667,7 @@ pub async fn execute(
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
// Print header messages
@@ -1079,6 +1080,7 @@ mod tests {
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
let resolved = resolver::resolve(&request)
@@ -1158,6 +1160,7 @@ mod tests {
block_abandoned: false,
root_branch_alias: None,
preferred_versions: indexmap::IndexMap::new(),
+ block_insecure: false,
};
let resolved = resolver::resolve(&request)
diff --git a/crates/mozart/src/commands/update.rs b/crates/mozart/src/commands/update.rs
index 3736266..0439cfa 100644
--- a/crates/mozart/src/commands/update.rs
+++ b/crates/mozart/src/commands/update.rs
@@ -1249,6 +1249,17 @@ pub async fn run(
.and_then(|a| a.get("block-abandoned"))
.and_then(|v| v.as_bool())
.unwrap_or(false);
+ // Mirrors `Composer\Advisory\AuditConfig::fromConfig`: `block-insecure`
+ // turns the security-advisory data into a hard filter — affected
+ // versions are dropped from the pool, so a root require with no
+ // unaffected candidates fails resolution before any side effects.
+ let block_insecure = composer_json
+ .extra_fields
+ .get("config")
+ .and_then(|c| c.get("audit"))
+ .and_then(|a| a.get("block-insecure"))
+ .and_then(|v| v.as_bool())
+ .unwrap_or(false);
// For `--minimal-changes`, feed the lock's pinned versions into the
// resolver as preferred-version overrides. The packages the user
@@ -1327,6 +1338,7 @@ pub async fn run(
block_abandoned,
root_branch_alias: extract_root_branch_alias(&composer_json),
preferred_versions,
+ block_insecure,
};
// Step 6: Print header and run resolver
@@ -1496,10 +1508,9 @@ pub async fn run(
// doesn't masquerade as a content update. When the source or dist type
// changed (`hg` → `git`, etc.), the new entry is left as-is so the
// change still emits the install-step Update operation.
- if update_mirrors
- && let Some(old) = &old_lock {
- apply_mirror_ref_overrides(&mut new_lock, old);
- }
+ if update_mirrors && let Some(old) = &old_lock {
+ apply_mirror_ref_overrides(&mut new_lock, old);
+ }
// Step 10: Compute and print change report
let changes = compute_update_changes(old_lock.as_ref(), &new_lock, dev_mode);
@@ -2476,6 +2487,7 @@ mod tests {
block_abandoned: false,
root_branch_alias: None,
preferred_versions: IndexMap::new(),
+ block_insecure: false,
};
let resolved = resolve(&request).await.expect("Resolution should succeed");