aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-07 11:20:23 +0900
committernsfisis <nsfisis@gmail.com>2026-06-07 11:20:23 +0900
commit54af47e286d0fb601e2e60aeb19002f6b7937574 (patch)
tree844c1ac44baefbdac7469d5ce9dfaa73b1e919d2 /crates/shirabe
parent3a6e69596d4f45ba1c50c6e932004e2160799d0c (diff)
downloadphp-shirabe-54af47e286d0fb601e2e60aeb19002f6b7937574.tar.gz
php-shirabe-54af47e286d0fb601e2e60aeb19002f6b7937574.tar.zst
php-shirabe-54af47e286d0fb601e2e60aeb19002f6b7937574.zip
feat(shirabe): resolve advisory instanceof TODOs via AnySecurityAdvisory
Add an Ignored variant to the advisory enum (renamed to AnySecurityAdvisory) so the PHP three-class hierarchy PartialSecurityAdvisory -> SecurityAdvisory -> IgnoredSecurityAdvisory maps one-to-one onto enum variants. Replace the hard-coded auditor downcasts with as_security_advisory() (PHP `instanceof SecurityAdvisory`, true for both full and ignored) and as_ignored(), implementing severity/cve/source ignore filtering, the toIgnoredAdvisory conversion, and the table/plain row output faithfully. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe')
-rw-r--r--crates/shirabe/src/advisory/any_security_advisory.rs52
-rw-r--r--crates/shirabe/src/advisory/auditor.rs199
-rw-r--r--crates/shirabe/src/advisory/ignored_security_advisory.rs6
-rw-r--r--crates/shirabe/src/advisory/mod.rs4
-rw-r--r--crates/shirabe/src/advisory/partial_or_full_security_advisory.rs25
-rw-r--r--crates/shirabe/src/advisory/partial_security_advisory.rs8
-rw-r--r--crates/shirabe/src/advisory/security_advisory.rs4
-rw-r--r--crates/shirabe/src/dependency_resolver/pool.rs12
-rw-r--r--crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs10
-rw-r--r--crates/shirabe/src/repository/advisory_provider_interface.rs4
-rw-r--r--crates/shirabe/src/repository/composer_repository.rs19
-rw-r--r--crates/shirabe/src/repository/package_repository.rs11
-rw-r--r--crates/shirabe/src/repository/repository_set.rs8
13 files changed, 189 insertions, 173 deletions
diff --git a/crates/shirabe/src/advisory/any_security_advisory.rs b/crates/shirabe/src/advisory/any_security_advisory.rs
new file mode 100644
index 0000000..c48df33
--- /dev/null
+++ b/crates/shirabe/src/advisory/any_security_advisory.rs
@@ -0,0 +1,52 @@
+use crate::advisory::IgnoredSecurityAdvisory;
+use crate::advisory::PartialSecurityAdvisory;
+use crate::advisory::SecurityAdvisory;
+use shirabe_semver::constraint::AnyConstraint;
+
+#[derive(Debug, Clone)]
+pub enum AnySecurityAdvisory {
+ Partial(PartialSecurityAdvisory),
+ Full(SecurityAdvisory),
+ Ignored(IgnoredSecurityAdvisory),
+}
+
+impl AnySecurityAdvisory {
+ pub fn advisory_id(&self) -> &str {
+ match self {
+ AnySecurityAdvisory::Partial(p) => &p.advisory_id,
+ AnySecurityAdvisory::Full(s) => s.advisory_id(),
+ AnySecurityAdvisory::Ignored(i) => i.as_security_advisory().advisory_id(),
+ }
+ }
+
+ pub fn package_name(&self) -> &str {
+ match self {
+ AnySecurityAdvisory::Partial(p) => &p.package_name,
+ AnySecurityAdvisory::Full(s) => s.package_name(),
+ AnySecurityAdvisory::Ignored(i) => i.as_security_advisory().package_name(),
+ }
+ }
+
+ pub fn affected_versions(&self) -> &AnyConstraint {
+ match self {
+ AnySecurityAdvisory::Partial(p) => &p.affected_versions,
+ AnySecurityAdvisory::Full(s) => s.affected_versions(),
+ AnySecurityAdvisory::Ignored(i) => i.as_security_advisory().affected_versions(),
+ }
+ }
+
+ pub fn as_security_advisory(&self) -> Option<&SecurityAdvisory> {
+ match self {
+ AnySecurityAdvisory::Partial(_) => None,
+ AnySecurityAdvisory::Full(s) => Some(s),
+ AnySecurityAdvisory::Ignored(i) => Some(i.as_security_advisory()),
+ }
+ }
+
+ pub fn as_ignored(&self) -> Option<&IgnoredSecurityAdvisory> {
+ match self {
+ AnySecurityAdvisory::Ignored(i) => Some(i),
+ _ => None,
+ }
+ }
+}
diff --git a/crates/shirabe/src/advisory/auditor.rs b/crates/shirabe/src/advisory/auditor.rs
index ffe1a12..d50fe70 100644
--- a/crates/shirabe/src/advisory/auditor.rs
+++ b/crates/shirabe/src/advisory/auditor.rs
@@ -6,12 +6,11 @@ use indexmap::IndexMap;
use shirabe_external_packages::composer::pcre::Preg;
use shirabe_external_packages::symfony::console::formatter::OutputFormatter;
use shirabe_php_shim::{
- DATE_ATOM, InvalidArgumentException, PhpMixed, array_all, array_any, array_key_exists,
- array_keys, array_reduce, get_class, is_string, sprintf, str_starts_with,
+ InvalidArgumentException, PhpMixed, array_all, array_any, array_key_exists, array_keys,
+ array_reduce, get_class, sprintf, str_starts_with,
};
-use crate::advisory::IgnoredSecurityAdvisory;
-use crate::advisory::PartialOrFullSecurityAdvisory;
+use crate::advisory::AnySecurityAdvisory;
use crate::advisory::SecurityAdvisory;
use crate::io::ConsoleIO;
use crate::io::IOInterface;
@@ -178,7 +177,7 @@ impl Auditor {
let error_or_warn = if warning_only { "warning" } else { "error" };
if affected_packages_count > 0 || ignored_advisories.len() > 0 {
let passes: Vec<(
- &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ &IndexMap<String, Vec<AnySecurityAdvisory>>,
String,
)> = vec![
(
@@ -239,12 +238,12 @@ impl Auditor {
Ok(audit_bitmask)
}
- /// @param array<string, array<SecurityAdvisory|PartialOrFullSecurityAdvisory>> $advisories
+ /// @param array<string, array<SecurityAdvisory|AnySecurityAdvisory>> $advisories
/// @param array<string, string|null> $ignoreList
/// @return bool
pub fn needs_complete_advisory_load(
&self,
- advisories: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ advisories: &IndexMap<String, Vec<AnySecurityAdvisory>>,
ignore_list: &IndexMap<String, Option<String>>,
) -> bool {
if advisories.len() == 0 {
@@ -252,20 +251,13 @@ impl Auditor {
}
// no partial advisories present
- let advisories_values: Vec<&Vec<PartialOrFullSecurityAdvisory>> =
- advisories.values().collect();
+ let advisories_values: Vec<&Vec<AnySecurityAdvisory>> = advisories.values().collect();
if array_all(
&advisories_values,
- |pkg_advisories: &&Vec<PartialOrFullSecurityAdvisory>| {
- array_all(
- pkg_advisories,
- |_advisory: &PartialOrFullSecurityAdvisory| {
- // TODO(phase-b): `$advisory instanceof SecurityAdvisory` — needs an advisory
- // enum or trait downcast; SecurityAdvisoriesResult currently only holds
- // PartialOrFullSecurityAdvisory so this is hard-coded to false
- false
- },
- )
+ |pkg_advisories: &&Vec<AnySecurityAdvisory>| {
+ array_all(pkg_advisories, |advisory: &AnySecurityAdvisory| {
+ advisory.as_security_advisory().is_some()
+ })
},
) {
return false;
@@ -309,7 +301,7 @@ impl Auditor {
pub fn process_advisories(
&self,
- all_advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ all_advisories: IndexMap<String, Vec<AnySecurityAdvisory>>,
ignore_list: &IndexMap<String, Option<String>>,
ignored_severities: &IndexMap<String, Option<String>>,
) -> ProcessAdvisoriesResult {
@@ -320,8 +312,8 @@ impl Auditor {
};
}
- let mut advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>> = IndexMap::new();
- let mut ignored: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>> = IndexMap::new();
+ let mut advisories: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ let mut ignored: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
let mut ignore_reason: Option<String> = None;
for (package, pkg_advisories) in all_advisories {
@@ -341,40 +333,30 @@ impl Auditor {
.unwrap_or(None);
}
- // TODO(phase-b): `$advisory instanceof SecurityAdvisory` — needs an advisory enum
- // or trait downcast; the block below is skipped while SecurityAdvisoriesResult
- // only holds PartialOrFullSecurityAdvisory
- let advisory_as_full: Option<&SecurityAdvisory> = None;
- if let Some(full) = advisory_as_full {
- if is_string(&PhpMixed::String(full.severity.clone().unwrap_or_default()))
- && array_key_exists(
- full.severity.as_deref().unwrap_or(""),
- ignored_severities,
- )
- {
- is_active = false;
- let sev = full.severity.as_deref().unwrap_or("");
- ignore_reason = ignored_severities
- .get(sev)
- .cloned()
- .unwrap_or_else(|| Some(format!("{} severity is ignored", sev)));
+ if let Some(full) = advisory.as_security_advisory() {
+ if let Some(severity) = &full.severity {
+ if array_key_exists(severity, ignored_severities) {
+ is_active = false;
+ ignore_reason = ignored_severities
+ .get(severity)
+ .cloned()
+ .flatten()
+ .or_else(|| Some(format!("{} severity is ignored", severity)));
+ }
}
- if is_string(&PhpMixed::String(full.cve.clone().unwrap_or_default()))
- && array_key_exists(full.cve.as_deref().unwrap_or(""), ignore_list)
- {
- is_active = false;
- ignore_reason = ignore_list
- .get(full.cve.as_deref().unwrap_or(""))
- .cloned()
- .unwrap_or(None);
+ if let Some(cve) = &full.cve {
+ if array_key_exists(cve, ignore_list) {
+ is_active = false;
+ ignore_reason = ignore_list.get(cve).cloned().flatten();
+ }
}
for source in &full.sources {
let remote_id = source.get("remoteId").cloned().unwrap_or_default();
if array_key_exists(&remote_id, ignore_list) {
is_active = false;
- ignore_reason = ignore_list.get(&remote_id).cloned().unwrap_or(None);
+ ignore_reason = ignore_list.get(&remote_id).cloned().flatten();
break;
}
}
@@ -390,9 +372,12 @@ impl Auditor {
// Partial security advisories only used in summary mode
// and in that case we do not need to cast the object.
- // TODO(phase-b): `$advisory instanceof SecurityAdvisory` -> $advisory->toIgnoredAdvisory($ignoreReason)
- let _: Option<IgnoredSecurityAdvisory> = None;
- let _ = &ignore_reason;
+ let advisory = if advisory.as_security_advisory().is_some() {
+ let full = advisory.as_security_advisory().unwrap();
+ AnySecurityAdvisory::Ignored(full.to_ignored_advisory(ignore_reason.clone()))
+ } else {
+ advisory
+ };
ignored
.entry(package.clone())
@@ -410,7 +395,7 @@ impl Auditor {
/// @return array{int, int} Count of affected packages and total count of advisories
fn count_advisories(
&self,
- advisories: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ advisories: &IndexMap<String, Vec<AnySecurityAdvisory>>,
) -> (i64, i64) {
let mut count: i64 = 0;
for package_advisories in advisories.values() {
@@ -425,7 +410,7 @@ impl Auditor {
fn output_advisories(
&self,
io: &mut dyn IOInterface,
- advisories: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ advisories: &IndexMap<String, Vec<AnySecurityAdvisory>>,
format: &str,
) -> Result<()> {
match format {
@@ -463,7 +448,7 @@ impl Auditor {
fn output_advisories_table(
&self,
io: &ConsoleIO,
- advisories: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ advisories: &IndexMap<String, Vec<AnySecurityAdvisory>>,
) {
for package_advisories in advisories.values() {
for advisory in package_advisories {
@@ -477,31 +462,43 @@ impl Auditor {
"Affected versions".to_string(),
"Reported at".to_string(),
];
- // TODO(phase-b): advisory typed PartialOrFullSecurityAdvisory; PHP accesses
- // SecurityAdvisory fields (title, link, reportedAt, etc.)
- let _ = advisory;
- let row: Vec<String> = vec![
- /* advisory.packageName */ String::new(),
- /* self.get_severity(advisory) */ String::new(),
- /* self.get_advisory_id(advisory) */ String::new(),
- /* self.get_cve(advisory) */ String::new(),
- /* advisory.title */ String::new(),
- /* self.get_url(advisory) */ String::new(),
- /* advisory.affectedVersions.getPrettyString() */ String::new(),
- /* advisory.reportedAt.format(DATE_ATOM) */ String::new(),
+ let sa = advisory
+ .as_security_advisory()
+ .expect("output_advisories_table only receives full advisories");
+ let mut row: Vec<String> = vec![
+ sa.package_name().to_string(),
+ self.get_severity(sa),
+ self.get_advisory_id(sa),
+ self.get_cve(sa),
+ sa.title.clone(),
+ self.get_url(sa),
+ sa.affected_versions().get_pretty_string(),
+ // TODO(phase-b): PHP uses `$advisory->reportedAt->format(DATE_ATOM)`, but
+ // shim DATE_ATOM ("Y-m-d\TH:i:sP") is a PHP format string incompatible with
+ // chrono. Using the chrono equivalent directly; revisit once a PHP-style date
+ // formatter exists (see also locker.rs DATE_RFC3339).
+ sa.reported_at.format("%Y-%m-%dT%H:%M:%S%:z").to_string(),
];
- let _ = DATE_ATOM;
- // TODO(phase-b): `$advisory instanceof IgnoredSecurityAdvisory` downcast
- let advisory_as_ignored: Option<&IgnoredSecurityAdvisory> = None;
- if let Some(_ignored) = advisory_as_ignored {
+ if let Some(ignored) = advisory.as_ignored() {
headers.push("Ignore reason".to_string());
- // row.push(ignored.ignore_reason.clone().unwrap_or_else(|| "None specified".to_string()));
+ row.push(
+ ignored
+ .ignore_reason
+ .clone()
+ .unwrap_or_else(|| "None specified".to_string()),
+ );
}
- let _ = row;
io.get_table()
.set_horizontal(true)
.set_headers(headers.into_iter().map(|h| h.into()).collect())
- .add_row(ConsoleIO::sanitize(PhpMixed::Null, false))
+ .add_row(ConsoleIO::sanitize(
+ PhpMixed::List(
+ row.into_iter()
+ .map(|s| Box::new(PhpMixed::String(s)))
+ .collect(),
+ ),
+ false,
+ ))
.set_column_width(1, 80)
.set_column_max_width(1, 80)
.render();
@@ -513,7 +510,7 @@ impl Auditor {
fn output_advisories_plain(
&self,
io: &mut dyn IOInterface,
- advisories: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ advisories: &IndexMap<String, Vec<AnySecurityAdvisory>>,
) {
let mut error: Vec<String> = vec![];
let mut first_advisory = true;
@@ -522,40 +519,34 @@ impl Auditor {
if !first_advisory {
error.push("--------".to_string());
}
- // TODO(phase-b): advisory typed PartialOrFullSecurityAdvisory; PHP accesses
- // SecurityAdvisory fields
- let _ = advisory;
- error.push(format!("Package: {}", /* advisory.packageName */ ""));
- error.push(format!(
- "Severity: {}",
- /* self.get_severity(advisory) */ ""
- ));
- error.push(format!(
- "Advisory ID: {}",
- /* self.get_advisory_id(advisory) */ ""
- ));
- error.push(format!("CVE: {}", /* self.get_cve(advisory) */ ""));
- error.push(format!(
- "Title: {}",
- OutputFormatter::escape(/* advisory.title */ "")
- ));
- error.push(format!("URL: {}", /* self.get_url(advisory) */ ""));
+ let sa = advisory
+ .as_security_advisory()
+ .expect("output_advisories_plain only receives full advisories");
+ error.push(format!("Package: {}", sa.package_name()));
+ error.push(format!("Severity: {}", self.get_severity(sa)));
+ error.push(format!("Advisory ID: {}", self.get_advisory_id(sa)));
+ error.push(format!("CVE: {}", self.get_cve(sa)));
+ error.push(format!("Title: {}", OutputFormatter::escape(&sa.title)));
+ error.push(format!("URL: {}", self.get_url(sa)));
error.push(format!(
"Affected versions: {}",
- OutputFormatter::escape(
- /* advisory.affectedVersions.getPrettyString() */ ""
- )
+ OutputFormatter::escape(&sa.affected_versions().get_pretty_string())
));
error.push(format!(
"Reported at: {}",
- /* advisory.reportedAt.format(DATE_ATOM) */ ""
+ // TODO(phase-b): PHP uses `$advisory->reportedAt->format(DATE_ATOM)`, but
+ // shim DATE_ATOM ("Y-m-d\TH:i:sP") is a PHP format string incompatible with
+ // chrono. Using the chrono equivalent directly; revisit once a PHP-style date
+ // formatter exists (see also locker.rs DATE_RFC3339).
+ sa.reported_at.format("%Y-%m-%dT%H:%M:%S%:z")
));
- // TODO(phase-b): `$advisory instanceof IgnoredSecurityAdvisory` downcast
- let advisory_as_ignored: Option<&IgnoredSecurityAdvisory> = None;
- if let Some(_ignored) = advisory_as_ignored {
+ if let Some(ignored) = advisory.as_ignored() {
error.push(format!(
"Ignore reason: {}",
- /* ignored.ignore_reason.unwrap_or("None specified") */ ""
+ ignored
+ .ignore_reason
+ .clone()
+ .unwrap_or_else(|| "None specified".to_string())
));
}
first_advisory = false;
@@ -680,9 +671,7 @@ impl Auditor {
}
fn get_advisory_id(&self, advisory: &SecurityAdvisory) -> String {
- // TODO(phase-b): advisory.advisory_id lives on inner PartialOrFullSecurityAdvisory
- let advisory_id: &str = "";
- let _ = advisory;
+ let advisory_id = advisory.advisory_id();
if str_starts_with(advisory_id, "PKSA-") {
return format!(
"<href=https://packagist.org/security-advisories/{}>{}</>",
@@ -740,6 +729,6 @@ impl Auditor {
#[derive(Debug)]
pub struct ProcessAdvisoriesResult {
- pub advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
- pub ignored_advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ pub advisories: IndexMap<String, Vec<AnySecurityAdvisory>>,
+ pub ignored_advisories: IndexMap<String, Vec<AnySecurityAdvisory>>,
}
diff --git a/crates/shirabe/src/advisory/ignored_security_advisory.rs b/crates/shirabe/src/advisory/ignored_security_advisory.rs
index 140c00b..fa1f8ae 100644
--- a/crates/shirabe/src/advisory/ignored_security_advisory.rs
+++ b/crates/shirabe/src/advisory/ignored_security_advisory.rs
@@ -6,7 +6,7 @@ use indexmap::IndexMap;
use shirabe_php_shim::PhpMixed;
use shirabe_semver::constraint::AnyConstraint;
-#[derive(Debug, serde::Serialize)]
+#[derive(Debug, Clone, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct IgnoredSecurityAdvisory {
#[serde(flatten)]
@@ -44,4 +44,8 @@ impl IgnoredSecurityAdvisory {
ignore_reason,
}
}
+
+ pub fn as_security_advisory(&self) -> &SecurityAdvisory {
+ &self.inner
+ }
}
diff --git a/crates/shirabe/src/advisory/mod.rs b/crates/shirabe/src/advisory/mod.rs
index df80735..dbb90bd 100644
--- a/crates/shirabe/src/advisory/mod.rs
+++ b/crates/shirabe/src/advisory/mod.rs
@@ -1,13 +1,13 @@
+pub mod any_security_advisory;
pub mod audit_config;
pub mod auditor;
pub mod ignored_security_advisory;
-pub mod partial_or_full_security_advisory;
pub mod partial_security_advisory;
pub mod security_advisory;
+pub use any_security_advisory::*;
pub use audit_config::*;
pub use auditor::*;
pub use ignored_security_advisory::*;
-pub use partial_or_full_security_advisory::*;
pub use partial_security_advisory::*;
pub use security_advisory::*;
diff --git a/crates/shirabe/src/advisory/partial_or_full_security_advisory.rs b/crates/shirabe/src/advisory/partial_or_full_security_advisory.rs
deleted file mode 100644
index bb1df78..0000000
--- a/crates/shirabe/src/advisory/partial_or_full_security_advisory.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use crate::advisory::PartialSecurityAdvisory;
-use crate::advisory::SecurityAdvisory;
-use shirabe_semver::constraint::AnyConstraint;
-
-#[derive(Debug, Clone)]
-pub enum PartialOrFullSecurityAdvisory {
- Partial(PartialSecurityAdvisory),
- Full(SecurityAdvisory),
-}
-
-impl PartialOrFullSecurityAdvisory {
- pub fn advisory_id(&self) -> &str {
- match self {
- PartialOrFullSecurityAdvisory::Partial(p) => &p.advisory_id,
- PartialOrFullSecurityAdvisory::Full(s) => s.advisory_id(),
- }
- }
-
- pub fn affected_versions(&self) -> &AnyConstraint {
- match self {
- PartialOrFullSecurityAdvisory::Partial(p) => &p.affected_versions,
- PartialOrFullSecurityAdvisory::Full(s) => s.affected_versions(),
- }
- }
-}
diff --git a/crates/shirabe/src/advisory/partial_security_advisory.rs b/crates/shirabe/src/advisory/partial_security_advisory.rs
index 8815103..2062570 100644
--- a/crates/shirabe/src/advisory/partial_security_advisory.rs
+++ b/crates/shirabe/src/advisory/partial_security_advisory.rs
@@ -1,6 +1,6 @@
//! ref: composer/src/Composer/Advisory/PartialSecurityAdvisory.php
-use crate::advisory::PartialOrFullSecurityAdvisory;
+use crate::advisory::AnySecurityAdvisory;
use crate::advisory::SecurityAdvisory;
use crate::package::version::VersionParser;
use anyhow::Result;
@@ -32,7 +32,7 @@ impl PartialSecurityAdvisory {
package_name: &str,
data: &IndexMap<String, PhpMixed>,
parser: &VersionParser,
- ) -> Result<PartialOrFullSecurityAdvisory> {
+ ) -> Result<AnySecurityAdvisory> {
let affected_versions_str = data["affectedVersions"].as_string().unwrap_or("");
let constraint: AnyConstraint = match parser.parse_constraints(affected_versions_str) {
@@ -95,10 +95,10 @@ impl PartialSecurityAdvisory {
.and_then(|v| v.as_string())
.map(|s| s.to_string()),
);
- return Ok(PartialOrFullSecurityAdvisory::Full(advisory));
+ return Ok(AnySecurityAdvisory::Full(advisory));
}
- Ok(PartialOrFullSecurityAdvisory::Partial(Self {
+ Ok(AnySecurityAdvisory::Partial(Self {
advisory_id: data["advisoryId"].as_string().unwrap_or("").to_string(),
package_name: package_name.to_string(),
affected_versions: constraint,
diff --git a/crates/shirabe/src/advisory/security_advisory.rs b/crates/shirabe/src/advisory/security_advisory.rs
index c766e0f..5cb5c59 100644
--- a/crates/shirabe/src/advisory/security_advisory.rs
+++ b/crates/shirabe/src/advisory/security_advisory.rs
@@ -48,6 +48,10 @@ impl SecurityAdvisory {
&self.inner.advisory_id
}
+ pub fn package_name(&self) -> &str {
+ &self.inner.package_name
+ }
+
pub fn affected_versions(&self) -> &AnyConstraint {
&self.inner.affected_versions
}
diff --git a/crates/shirabe/src/dependency_resolver/pool.rs b/crates/shirabe/src/dependency_resolver/pool.rs
index 91c3e31..06878e1 100644
--- a/crates/shirabe/src/dependency_resolver/pool.rs
+++ b/crates/shirabe/src/dependency_resolver/pool.rs
@@ -8,7 +8,7 @@ use shirabe_semver::compiling_matcher::CompilingMatcher;
use shirabe_semver::constraint::AnyConstraint;
use shirabe_semver::constraint::SimpleConstraint;
-use crate::advisory::PartialOrFullSecurityAdvisory;
+use crate::advisory::AnySecurityAdvisory;
use crate::package::BasePackage;
use crate::package::BasePackageHandle;
use crate::package::version::VersionParser;
@@ -31,8 +31,7 @@ pub struct Pool {
/// @var array<string, array<string, string>> Map of package object hash => removed normalized versions => removed pretty version
pub(crate) removed_versions_by_package: IndexMap<String, IndexMap<String, String>>,
/// @var array<string, array<string, array<SecurityAdvisory|PartialSecurityAdvisory>>> Map of package name => normalized version => security advisories
- security_removed_versions:
- IndexMap<String, IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>>,
+ security_removed_versions: IndexMap<String, IndexMap<String, Vec<AnySecurityAdvisory>>>,
/// @var array<string, array<string, string>> Map of package name => normalized version => pretty version
abandoned_removed_versions: IndexMap<String, IndexMap<String, String>>,
}
@@ -49,10 +48,7 @@ impl Pool {
unacceptable_fixed_or_locked_packages: Vec<BasePackageHandle>,
removed_versions: IndexMap<String, IndexMap<String, String>>,
removed_versions_by_package: IndexMap<String, IndexMap<String, String>>,
- security_removed_versions: IndexMap<
- String,
- IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
- >,
+ security_removed_versions: IndexMap<String, IndexMap<String, Vec<AnySecurityAdvisory>>>,
abandoned_removed_versions: IndexMap<String, IndexMap<String, String>>,
) -> Self {
let mut this = Self {
@@ -189,7 +185,7 @@ impl Pool {
/// @return array<string, array<string, array<SecurityAdvisory|PartialSecurityAdvisory>>>
pub fn get_all_security_removed_package_versions(
&self,
- ) -> &IndexMap<String, IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>> {
+ ) -> &IndexMap<String, IndexMap<String, Vec<AnySecurityAdvisory>>> {
&self.security_removed_versions
}
diff --git a/crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs b/crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs
index 3136ce5..80769bb 100644
--- a/crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs
+++ b/crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs
@@ -1,8 +1,8 @@
//! ref: composer/src/Composer/DependencyResolver/SecurityAdvisoryPoolFilter.php
+use crate::advisory::AnySecurityAdvisory;
use crate::advisory::AuditConfig;
use crate::advisory::Auditor;
-use crate::advisory::PartialOrFullSecurityAdvisory;
use crate::dependency_resolver::Pool;
use crate::dependency_resolver::Request;
use crate::package::BasePackageHandle;
@@ -86,7 +86,7 @@ impl SecurityAdvisoryPoolFilter {
let mut packages: Vec<BasePackageHandle> = vec![];
let mut security_removed_versions: IndexMap<
String,
- IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ IndexMap<String, Vec<AnySecurityAdvisory>>,
> = IndexMap::new();
let mut abandoned_removed_versions: IndexMap<String, IndexMap<String, String>> =
IndexMap::new();
@@ -144,13 +144,13 @@ impl SecurityAdvisoryPoolFilter {
fn get_matching_advisories(
&self,
package: BasePackageHandle,
- advisory_map: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
- ) -> Vec<PartialOrFullSecurityAdvisory> {
+ advisory_map: &IndexMap<String, Vec<AnySecurityAdvisory>>,
+ ) -> Vec<AnySecurityAdvisory> {
if package.is_dev() {
return vec![];
}
- let mut matching_advisories: Vec<PartialOrFullSecurityAdvisory> = vec![];
+ let mut matching_advisories: Vec<AnySecurityAdvisory> = vec![];
for package_name in package.get_names(false) {
if !advisory_map.contains_key(&package_name) {
continue;
diff --git a/crates/shirabe/src/repository/advisory_provider_interface.rs b/crates/shirabe/src/repository/advisory_provider_interface.rs
index 6b94ca9..9d0c5ac 100644
--- a/crates/shirabe/src/repository/advisory_provider_interface.rs
+++ b/crates/shirabe/src/repository/advisory_provider_interface.rs
@@ -1,13 +1,13 @@
//! ref: composer/src/Composer/Repository/AdvisoryProviderInterface.php
-use crate::advisory::{PartialOrFullSecurityAdvisory, PartialSecurityAdvisory, SecurityAdvisory};
+use crate::advisory::{AnySecurityAdvisory, PartialSecurityAdvisory, SecurityAdvisory};
use indexmap::IndexMap;
use shirabe_semver::constraint::AnyConstraint;
#[derive(Debug)]
pub struct SecurityAdvisoryResult {
pub names_found: Vec<String>,
- pub advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ pub advisories: IndexMap<String, Vec<AnySecurityAdvisory>>,
}
pub trait AdvisoryProviderInterface {
diff --git a/crates/shirabe/src/repository/composer_repository.rs b/crates/shirabe/src/repository/composer_repository.rs
index 0d2fa2f..f9fa551 100644
--- a/crates/shirabe/src/repository/composer_repository.rs
+++ b/crates/shirabe/src/repository/composer_repository.rs
@@ -14,7 +14,7 @@ use shirabe_semver::constraint::AnyConstraint;
use shirabe_semver::constraint::MatchAllConstraint;
use shirabe_semver::constraint::SimpleConstraint;
-use crate::advisory::{PartialOrFullSecurityAdvisory, PartialSecurityAdvisory};
+use crate::advisory::{AnySecurityAdvisory, PartialSecurityAdvisory};
use crate::cache::Cache;
use crate::config::Config;
use crate::downloader::TransportException;
@@ -896,7 +896,7 @@ impl ComposerRepository {
});
}
- let mut advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>> = IndexMap::new();
+ let mut advisories: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
let mut names_found: IndexMap<String, bool> = IndexMap::new();
let api_url = self
@@ -919,9 +919,9 @@ impl ComposerRepository {
let create = |data: &IndexMap<String, PhpMixed>,
name: &str,
package_constraint_map: &IndexMap<String, AnyConstraint>|
- -> anyhow::Result<Option<PartialOrFullSecurityAdvisory>> {
+ -> anyhow::Result<Option<AnySecurityAdvisory>> {
let advisory = PartialSecurityAdvisory::create(name, data, &parser)?;
- let is_full = matches!(advisory, PartialOrFullSecurityAdvisory::Full(_));
+ let is_full = matches!(advisory, AnySecurityAdvisory::Full(_));
if !allow_partial_advisories && !is_full {
let data_mixed = PhpMixed::Array(
data.iter()
@@ -940,10 +940,7 @@ impl ComposerRepository {
}
.into());
}
- let affected_versions: &AnyConstraint = match &advisory {
- PartialOrFullSecurityAdvisory::Partial(p) => &p.affected_versions,
- PartialOrFullSecurityAdvisory::Full(p) => p.affected_versions(),
- };
+ let affected_versions: &AnyConstraint = advisory.affected_versions();
let constraint = package_constraint_map.get(name);
if let Some(c) = constraint {
if !affected_versions.matches(c) {
@@ -995,7 +992,7 @@ impl ComposerRepository {
names_found.insert(name.clone(), true);
if !sec_advs_arr.is_empty() {
- let mut entries: Vec<PartialOrFullSecurityAdvisory> = Vec::new();
+ let mut entries: Vec<AnySecurityAdvisory> = Vec::new();
for (_k, data_mixed) in sec_advs_arr.iter() {
if let Some(data) = data_mixed.as_array() {
let data_map: IndexMap<String, PhpMixed> = data
@@ -1086,7 +1083,7 @@ impl ComposerRepository {
None => continue,
};
if !list.is_empty() {
- let mut entries: Vec<PartialOrFullSecurityAdvisory> = Vec::new();
+ let mut entries: Vec<AnySecurityAdvisory> = Vec::new();
for data_mixed in list.iter() {
if let Some(data) = data_mixed.as_array() {
let data_map: IndexMap<String, PhpMixed> = data
@@ -1106,7 +1103,7 @@ impl ComposerRepository {
}
}
- let advisories_filtered: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>> = advisories
+ let advisories_filtered: IndexMap<String, Vec<AnySecurityAdvisory>> = advisories
.into_iter()
.filter(|(_, adv)| !adv.is_empty())
.collect();
diff --git a/crates/shirabe/src/repository/package_repository.rs b/crates/shirabe/src/repository/package_repository.rs
index c264eaf..273cde0 100644
--- a/crates/shirabe/src/repository/package_repository.rs
+++ b/crates/shirabe/src/repository/package_repository.rs
@@ -1,7 +1,7 @@
//! ref: composer/src/Composer/Repository/PackageRepository.php
use crate::advisory::SecurityAdvisory;
-use crate::advisory::{PartialOrFullSecurityAdvisory, PartialSecurityAdvisory};
+use crate::advisory::{AnySecurityAdvisory, PartialSecurityAdvisory};
use crate::package::loader::ArrayLoader;
use crate::package::loader::ValidatingArrayLoader;
use crate::package::version::VersionParser;
@@ -93,7 +93,7 @@ impl AdvisoryProviderInterface for PackageRepository {
) -> anyhow::Result<SecurityAdvisoryResult> {
let parser = VersionParser::new();
- let mut advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>> = IndexMap::new();
+ let mut advisories: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
for (package_name, package_advisories) in &self.security_advisories {
let Some(package_constraint) = package_constraint_map.get(package_name) else {
continue;
@@ -103,7 +103,7 @@ impl AdvisoryProviderInterface for PackageRepository {
PhpMixed::List(list) => list,
_ => continue,
};
- let mut items: Vec<PartialOrFullSecurityAdvisory> = Vec::new();
+ let mut items: Vec<AnySecurityAdvisory> = Vec::new();
for data in list {
let data_map: IndexMap<String, PhpMixed> = match data.as_ref() {
PhpMixed::Array(m) => m.iter().map(|(k, v)| (k.clone(), *v.clone())).collect(),
@@ -114,8 +114,7 @@ impl AdvisoryProviderInterface for PackageRepository {
Ok(a) => a,
Err(_) => continue,
};
- if !allow_partial_advisories
- && matches!(advisory, PartialOrFullSecurityAdvisory::Partial(_))
+ if !allow_partial_advisories && matches!(advisory, AnySecurityAdvisory::Partial(_))
{
return Err(anyhow::anyhow!(RuntimeException {
message: format!(
@@ -138,7 +137,7 @@ impl AdvisoryProviderInterface for PackageRepository {
}
let names_found: Vec<String> = advisories.keys().cloned().collect();
- let advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>> = advisories
+ let advisories: IndexMap<String, Vec<AnySecurityAdvisory>> = advisories
.into_iter()
.filter(|(_, adv)| !adv.is_empty())
.collect();
diff --git a/crates/shirabe/src/repository/repository_set.rs b/crates/shirabe/src/repository/repository_set.rs
index 367a46a..62b25cb 100644
--- a/crates/shirabe/src/repository/repository_set.rs
+++ b/crates/shirabe/src/repository/repository_set.rs
@@ -13,7 +13,7 @@ use shirabe_semver::constraint::MatchAllConstraint;
use shirabe_semver::constraint::MultiConstraint;
use shirabe_semver::constraint::SimpleConstraint;
-use crate::advisory::{PartialOrFullSecurityAdvisory, PartialSecurityAdvisory, SecurityAdvisory};
+use crate::advisory::{AnySecurityAdvisory, PartialSecurityAdvisory, SecurityAdvisory};
use crate::dependency_resolver::Pool;
use crate::dependency_resolver::PoolBuilder;
use crate::dependency_resolver::PoolOptimizer;
@@ -371,8 +371,8 @@ impl RepositorySet {
allow_partial_advisories: bool,
ignore_unreachable: bool,
unreachable_repos: &mut Vec<String>,
- ) -> Result<IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>> {
- let mut repo_advisories: Vec<IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>> = vec![];
+ ) -> Result<IndexMap<String, Vec<AnySecurityAdvisory>>> {
+ let mut repo_advisories: Vec<IndexMap<String, Vec<AnySecurityAdvisory>>> = vec![];
for repository in &self.repositories {
let attempt: Result<()> = (|| -> Result<()> {
let mut repo_ref = repository.borrow_mut();
@@ -664,6 +664,6 @@ impl RepositorySet {
#[derive(Debug)]
pub struct SecurityAdvisoriesResult {
- pub advisories: IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>,
+ pub advisories: IndexMap<String, Vec<AnySecurityAdvisory>>,
pub unreachable_repos: Vec<String>,
}