aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-14 19:56:23 +0900
committernsfisis <nsfisis@gmail.com>2026-05-14 19:56:23 +0900
commit6ffb4b4db1da067ca88f98d8164940a570c2b2af (patch)
tree3011821fd2652c867a0701f0a634bdf41b245538
parent9a65b4a9d24fe9b5759df05d4c2b06a6d2186dec (diff)
downloadphp-shirabe-6ffb4b4db1da067ca88f98d8164940a570c2b2af.tar.gz
php-shirabe-6ffb4b4db1da067ca88f98d8164940a570c2b2af.tar.zst
php-shirabe-6ffb4b4db1da067ca88f98d8164940a570c2b2af.zip
feat(port): port PartialSecurityAdvisory.php
-rw-r--r--crates/shirabe-php-shim/src/lib.rs4
-rw-r--r--crates/shirabe/src/advisory/partial_security_advisory.rs88
2 files changed, 92 insertions, 0 deletions
diff --git a/crates/shirabe-php-shim/src/lib.rs b/crates/shirabe-php-shim/src/lib.rs
index 758dd1c..56b29e5 100644
--- a/crates/shirabe-php-shim/src/lib.rs
+++ b/crates/shirabe-php-shim/src/lib.rs
@@ -220,6 +220,10 @@ impl PharData {
}
}
+pub trait JsonSerializable {
+ fn json_serialize(&self) -> PhpMixed;
+}
+
pub fn class_exists(name: &str) -> bool {
todo!()
}
diff --git a/crates/shirabe/src/advisory/partial_security_advisory.rs b/crates/shirabe/src/advisory/partial_security_advisory.rs
index 894ed17..63fe998 100644
--- a/crates/shirabe/src/advisory/partial_security_advisory.rs
+++ b/crates/shirabe/src/advisory/partial_security_advisory.rs
@@ -1 +1,89 @@
//! ref: composer/src/Composer/Advisory/PartialSecurityAdvisory.php
+
+use anyhow::Result;
+use chrono::{DateTime, TimeZone, Utc};
+use indexmap::IndexMap;
+use shirabe_external_packages::composer::pcre::preg::Preg;
+use shirabe_php_shim::{JsonSerializable, PhpMixed, UnexpectedValueException};
+use shirabe_semver::constraint::constraint::Constraint;
+use shirabe_semver::constraint::constraint_interface::ConstraintInterface;
+use shirabe_semver::version_parser::VersionParser;
+use crate::advisory::security_advisory::SecurityAdvisory;
+
+#[derive(Debug)]
+pub struct PartialSecurityAdvisory {
+ pub advisory_id: String,
+ pub package_name: String,
+ pub affected_versions: Box<dyn ConstraintInterface>,
+}
+
+impl PartialSecurityAdvisory {
+ pub fn create(
+ package_name: &str,
+ data: &IndexMap<String, PhpMixed>,
+ parser: &VersionParser,
+ ) -> Result<Box<dyn std::any::Any>> {
+ let affected_versions_str = data["affectedVersions"].as_string().unwrap_or("");
+
+ let constraint: Box<dyn ConstraintInterface> = match parser.parse_constraints(affected_versions_str) {
+ Ok(c) => c,
+ Err(_) => {
+ let affected_version = Preg::replace(r"(^[>=<^~]*[\d.]+).*", "$1", affected_versions_str);
+ match parser.parse_constraints(&affected_version) {
+ Ok(c) => c,
+ Err(_) => Box::new(Constraint::new("==", "0.0.0-invalid-version")),
+ }
+ }
+ };
+
+ let has_full_data = data.contains_key("title")
+ && data.contains_key("sources")
+ && data.contains_key("reportedAt");
+
+ if has_full_data {
+ let reported_at: DateTime<Utc> = Utc
+ .datetime_from_str(
+ data["reportedAt"].as_string().unwrap_or(""),
+ "%Y-%m-%dT%H:%M:%S+00:00",
+ )
+ .unwrap_or_default();
+ let advisory = SecurityAdvisory::new(
+ package_name.to_string(),
+ data["advisoryId"].as_string().unwrap_or("").to_string(),
+ constraint,
+ data["title"].as_string().unwrap_or("").to_string(),
+ data["sources"].clone(),
+ reported_at,
+ data.get("cve").and_then(|v| v.as_string()).map(|s| s.to_string()),
+ data.get("link").and_then(|v| v.as_string()).map(|s| s.to_string()),
+ data.get("severity").and_then(|v| v.as_string()).map(|s| s.to_string()),
+ );
+ return Ok(Box::new(advisory));
+ }
+
+ Ok(Box::new(Self {
+ advisory_id: data["advisoryId"].as_string().unwrap_or("").to_string(),
+ package_name: package_name.to_string(),
+ affected_versions: constraint,
+ }))
+ }
+
+ pub fn new(
+ package_name: String,
+ advisory_id: String,
+ affected_versions: Box<dyn ConstraintInterface>,
+ ) -> Self {
+ Self { advisory_id, package_name, affected_versions }
+ }
+}
+
+impl JsonSerializable for PartialSecurityAdvisory {
+ fn json_serialize(&self) -> PhpMixed {
+ use indexmap::IndexMap;
+ let mut data: IndexMap<String, Box<PhpMixed>> = IndexMap::new();
+ data.insert("advisoryId".to_string(), Box::new(PhpMixed::String(self.advisory_id.clone())));
+ data.insert("packageName".to_string(), Box::new(PhpMixed::String(self.package_name.clone())));
+ data.insert("affectedVersions".to_string(), Box::new(PhpMixed::String(self.affected_versions.get_pretty_string())));
+ PhpMixed::Array(data)
+ }
+}