aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/advisory
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
committernsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
commit822d9a872807a92a5337ee8b7bab96dc9845cdbb (patch)
tree4931365df5978caffade69cad2154718a9076f66 /crates/shirabe/tests/advisory
parentf691b864b687f251c3b266e8cff2774d730567ba (diff)
downloadphp-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.tar.gz
php-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.tar.zst
php-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.zip
test: port more test cases
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/advisory')
-rw-r--r--crates/shirabe/tests/advisory/auditor_test.rs150
1 files changed, 144 insertions, 6 deletions
diff --git a/crates/shirabe/tests/advisory/auditor_test.rs b/crates/shirabe/tests/advisory/auditor_test.rs
index ea0b3c8..038c675 100644
--- a/crates/shirabe/tests/advisory/auditor_test.rs
+++ b/crates/shirabe/tests/advisory/auditor_test.rs
@@ -1,33 +1,171 @@
//! ref: composer/tests/Composer/Test/Advisory/AuditorTest.php
+use chrono::Utc;
+use indexmap::IndexMap;
+use shirabe::advisory::AnySecurityAdvisory;
+use shirabe::advisory::Auditor;
+use shirabe::advisory::PartialSecurityAdvisory;
+use shirabe::advisory::SecurityAdvisory;
+use shirabe_semver::constraint::SimpleConstraint;
+
+fn constraint(operator: &str, version: &str) -> shirabe_semver::constraint::AnyConstraint {
+ SimpleConstraint::new(operator.to_string(), version.to_string(), None).into()
+}
+
+fn full_advisory() -> AnySecurityAdvisory {
+ let mut source: IndexMap<String, String> = IndexMap::new();
+ source.insert("name".to_string(), "foo".to_string());
+ source.insert("remoteId".to_string(), "remoteID".to_string());
+ AnySecurityAdvisory::Full(SecurityAdvisory::new(
+ "foo/bar".to_string(),
+ "123".to_string(),
+ constraint("=", "1.0.0.0"),
+ "test".to_string(),
+ vec![source],
+ Utc::now(),
+ None,
+ None,
+ None,
+ ))
+}
+
+fn full_advisory_with_id(advisory_id: &str) -> AnySecurityAdvisory {
+ let mut source: IndexMap<String, String> = IndexMap::new();
+ source.insert("name".to_string(), "foo".to_string());
+ source.insert("remoteId".to_string(), "remoteID".to_string());
+ AnySecurityAdvisory::Full(SecurityAdvisory::new(
+ "foo/bar".to_string(),
+ advisory_id.to_string(),
+ constraint("=", "1.0.0.0"),
+ "test".to_string(),
+ vec![source],
+ Utc::now(),
+ None,
+ None,
+ None,
+ ))
+}
+
+fn partial_advisory(advisory_id: &str) -> AnySecurityAdvisory {
+ AnySecurityAdvisory::Partial(PartialSecurityAdvisory::new(
+ "foo/bar".to_string(),
+ advisory_id.to_string(),
+ constraint("=", "1.0.0.0"),
+ ))
+}
+
+fn ignore_list(pairs: Vec<(&str, Option<&str>)>) -> IndexMap<String, Option<String>> {
+ pairs
+ .into_iter()
+ .map(|(k, v)| (k.to_string(), v.map(String::from)))
+ .collect()
+}
+
// These run the Auditor against a mocked HttpDownloader/IO and packages built from version
// constraints (parsed via a look-around regex the regex crate cannot compile).
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires PHPUnit getMockBuilder partial mock of ComposerRepository (hasSecurityAdvisories/getSecurityAdvisories) and BufferIO; no mocking infrastructure exists"]
fn test_audit() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires getIOMock with expects() output expectations and getMockBuilder mock of ComposerRepository; no mocking infrastructure exists"]
fn test_audit_with_ignore() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires getMockBuilder partial mock of RepositorySet (getMatchingSecurityAdvisories willReturnCallback); no mocking infrastructure exists"]
fn test_audit_with_ignore_unreachable() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore = "requires getIOMock with expects() output expectations and getMockBuilder mock of ComposerRepository; no mocking infrastructure exists"]
fn test_audit_with_ignore_severity() {
todo!()
}
#[test]
-#[ignore = "not yet ported (Auditor with mocked HttpDownloader/IO; constraint parsing uses a look-around regex)"]
+#[ignore]
fn test_needs_complete_advisory_load() {
- todo!()
+ let cases: Vec<(
+ IndexMap<String, Vec<AnySecurityAdvisory>>,
+ IndexMap<String, Option<String>>,
+ bool,
+ )> = vec![
+ // no filter or advisories
+ (IndexMap::new(), ignore_list(vec![]), false),
+ // packagist filters are IDs so work fine with partial advisories
+ (
+ IndexMap::new(),
+ ignore_list(vec![("PKSA-foo-bar", None)]),
+ false,
+ ),
+ // packagist filters are IDs so work fine with partial advisories/2
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert(
+ "vendor1/package1".to_string(),
+ vec![full_advisory(), partial_advisory("1234")],
+ );
+ m
+ },
+ ignore_list(vec![("PKSA-foo-bar", Some("this is fine 🔥"))]),
+ false,
+ ),
+ // no advisories no need to load any further
+ (
+ IndexMap::new(),
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ false,
+ ),
+ // no advisories no need to load any further/2
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert("vendor1/package1".to_string(), vec![]);
+ m
+ },
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ false,
+ ),
+ // CVE filter or other non-packagist ones might need to fully load for safety if partial advisories are present
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert(
+ "vendor1/package1".to_string(),
+ vec![full_advisory(), partial_advisory("1234")],
+ );
+ m
+ },
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ true,
+ ),
+ // filter does not trigger load if all advisories are fully loaded
+ (
+ {
+ let mut m: IndexMap<String, Vec<AnySecurityAdvisory>> = IndexMap::new();
+ m.insert("vendor1/package1".to_string(), vec![full_advisory()]);
+ m.insert(
+ "vendor1/package2".to_string(),
+ vec![full_advisory_with_id("1234")],
+ );
+ m
+ },
+ ignore_list(vec![("CVE-2025-1234", None)]),
+ false,
+ ),
+ ];
+
+ let auditor = Auditor;
+ for (advisories, ignore_list, expected) in cases {
+ assert_eq!(
+ expected,
+ auditor.needs_complete_advisory_load(&advisories, &ignore_list)
+ );
+ }
}