diff options
Diffstat (limited to 'crates/shirabe/src/dependency_resolver')
5 files changed, 142 insertions, 47 deletions
diff --git a/crates/shirabe/src/dependency_resolver/pool.rs b/crates/shirabe/src/dependency_resolver/pool.rs index ddb4df5..708930c 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::PartialSecurityAdvisory; +use crate::advisory::PartialOrFullSecurityAdvisory; use crate::package::BasePackage; use crate::package::BasePackageHandle; use crate::package::version::VersionParser; @@ -31,8 +31,8 @@ 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 - // TODO(phase-b): SecurityAdvisory|PartialSecurityAdvisory union — stored as PartialSecurityAdvisory base - security_removed_versions: IndexMap<String, IndexMap<String, Vec<PartialSecurityAdvisory>>>, + security_removed_versions: + IndexMap<String, IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>>, /// @var array<string, array<string, string>> Map of package name => normalized version => pretty version abandoned_removed_versions: IndexMap<String, IndexMap<String, String>>, } @@ -49,7 +49,10 @@ 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<PartialSecurityAdvisory>>>, + security_removed_versions: IndexMap< + String, + IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>, + >, abandoned_removed_versions: IndexMap<String, IndexMap<String, String>>, ) -> Self { let mut this = Self { @@ -151,7 +154,7 @@ impl Pool { ) { return package_with_security_advisories .iter() - .map(|advisory| advisory.advisory_id.clone()) + .map(|advisory| advisory.advisory_id().to_string()) .collect(); } } @@ -186,7 +189,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<PartialSecurityAdvisory>>> { + ) -> &IndexMap<String, IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>> { &self.security_removed_versions } diff --git a/crates/shirabe/src/dependency_resolver/pool_builder.rs b/crates/shirabe/src/dependency_resolver/pool_builder.rs index 18d2db4..1bbd51e 100644 --- a/crates/shirabe/src/dependency_resolver/pool_builder.rs +++ b/crates/shirabe/src/dependency_resolver/pool_builder.rs @@ -352,7 +352,7 @@ impl PoolBuilder { // filter vulnerable packages before optimizing the pool otherwise we may end up with inconsistent state where the optimizer took away versions // that were not vulnerable and now suddenly the vulnerable ones are removed and we are missing some versions to make it solvable - pool = self.run_security_advisory_filter(pool, &repositories, request); + pool = self.run_security_advisory_filter(pool, &repositories, request)?; pool = self.run_optimizer(request, pool); Intervals::clear(); @@ -1110,9 +1110,9 @@ impl PoolBuilder { pool: Pool, repositories: &Vec<RepositoryInterfaceHandle>, request: &Request, - ) -> Pool { + ) -> anyhow::Result<Pool> { if self.security_advisory_pool_filter.is_none() { - return pool; + return Ok(pool); } self.io.debug("Running security advisory pool filter.", &[]); @@ -1121,16 +1121,16 @@ impl PoolBuilder { let total = pool.get_packages().len() as f64; let repos_owned: Vec<RepositoryInterfaceHandle> = repositories.iter().cloned().collect(); - let pool = - self.security_advisory_pool_filter - .as_mut() - .unwrap() - .filter(pool, repos_owned, request); + let pool = self + .security_advisory_pool_filter + .as_mut() + .unwrap() + .filter(pool, repos_owned, request)?; let filtered = total - (pool.get_packages().len() as f64); if 0.0 == filtered { - return pool; + return Ok(pool); } self.io.write3( @@ -1154,6 +1154,6 @@ impl PoolBuilder { io_interface::VERY_VERBOSE, ); - pool + Ok(pool) } } diff --git a/crates/shirabe/src/dependency_resolver/pool_optimizer.rs b/crates/shirabe/src/dependency_resolver/pool_optimizer.rs index 18c8d01..7cba910 100644 --- a/crates/shirabe/src/dependency_resolver/pool_optimizer.rs +++ b/crates/shirabe/src/dependency_resolver/pool_optimizer.rs @@ -209,8 +209,7 @@ impl PoolOptimizer { pool.get_unacceptable_fixed_or_locked_packages().clone(), removed_versions, self.removed_versions_by_package.clone(), - // TODO(phase-b): PartialSecurityAdvisory is a PHP class (no Clone). Need shared ownership rework. - todo!("pool.get_all_security_removed_package_versions().clone()"), + pool.get_all_security_removed_package_versions().clone(), pool.get_all_abandoned_removed_package_versions().clone(), ) } diff --git a/crates/shirabe/src/dependency_resolver/rule_set_generator.rs b/crates/shirabe/src/dependency_resolver/rule_set_generator.rs index fece1e4..5979f63 100644 --- a/crates/shirabe/src/dependency_resolver/rule_set_generator.rs +++ b/crates/shirabe/src/dependency_resolver/rule_set_generator.rs @@ -309,9 +309,11 @@ impl RuleSetGenerator { for package in request.get_fixed_packages().values() { if package.get_id() == -1 { // fixed package was not added to the pool as it did not pass the stability requirements, this is fine - // TODO(phase-c): wire Pool::is_unacceptable_fixed_or_locked_package(package) here; - // the package handle and the pool's identity check are now both handle-based. - if todo!("is_unacceptable_fixed_or_locked_package with a request package handle") { + if self + .pool + .borrow() + .is_unacceptable_fixed_or_locked_package(package.clone()) + { continue; } 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 ec224b4..3136ce5 100644 --- a/crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs +++ b/crates/shirabe/src/dependency_resolver/security_advisory_pool_filter.rs @@ -2,12 +2,14 @@ use crate::advisory::AuditConfig; use crate::advisory::Auditor; -use crate::advisory::PartialSecurityAdvisory; +use crate::advisory::PartialOrFullSecurityAdvisory; use crate::dependency_resolver::Pool; use crate::dependency_resolver::Request; use crate::package::BasePackageHandle; +use crate::repository::PlatformRepository; +use crate::repository::RepositoryInterfaceHandle; +use crate::repository::RepositorySet; use indexmap::IndexMap; -use shirabe_semver::constraint::AnyConstraint; use shirabe_semver::constraint::SimpleConstraint; #[derive(Debug)] @@ -27,37 +29,128 @@ impl SecurityAdvisoryPoolFilter { pub fn filter( &self, pool: Pool, - repositories: Vec<crate::repository::RepositoryInterfaceHandle>, + repositories: Vec<RepositoryInterfaceHandle>, request: &Request, - ) -> Pool { - // TODO(phase-c): port the filter() body. Blockers: - // * RepositorySet::new takes 6 args; ConfigSourceInterface refactor pending - // * pool.get_packages() yields BasePackageHandle; widen to PackageInterfaceHandle - // (via .into()) where the audit/repo APIs expect PackageInterface. - // * Pool::new requires owned Vecs; clone the handles out of the existing pool. - // * advisory map element type mismatch (PhpMixed vs PartialSecurityAdvisory). - let _ = ( - pool, - repositories, - request, - &self.auditor, - &self.audit_config, + ) -> anyhow::Result<Pool> { + if !self.audit_config.block_insecure { + return Ok(pool); + } + + let mut repo_set = RepositorySet::new( + "stable", + IndexMap::new(), + vec![], + IndexMap::new(), + IndexMap::new(), + IndexMap::new(), ); - todo!("port SecurityAdvisoryPoolFilter::filter") + for repo in repositories { + repo_set.add_repository(repo)?; + } + + let mut packages_for_advisories: Vec<BasePackageHandle> = vec![]; + for package in pool.get_packages() { + if package.as_root().is_none() + && !PlatformRepository::is_platform_package(&package.get_name()) + && !request.is_locked_package(package.clone()) + { + packages_for_advisories.push(package.clone()); + } + } + + let mut all_advisories = repo_set.get_matching_security_advisories( + packages_for_advisories.clone(), + true, + true, + )?; + if self.auditor.needs_complete_advisory_load( + &all_advisories.advisories, + &self.audit_config.ignore_list_for_blocking, + ) { + all_advisories = repo_set.get_matching_security_advisories( + packages_for_advisories.clone(), + false, + true, + )?; + } + + let advisory_map = self + .auditor + .process_advisories( + all_advisories.advisories, + &self.audit_config.ignore_list_for_blocking, + &self.audit_config.ignore_severity_for_blocking, + ) + .advisories; + + let mut packages: Vec<BasePackageHandle> = vec![]; + let mut security_removed_versions: IndexMap< + String, + IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>, + > = IndexMap::new(); + let mut abandoned_removed_versions: IndexMap<String, IndexMap<String, String>> = + IndexMap::new(); + for package in pool.get_packages() { + if self.audit_config.block_abandoned + && self + .auditor + .filter_abandoned_packages( + &[package.clone()], + &self.audit_config.ignore_abandoned_for_blocking, + )? + .len() + != 0 + { + for package_name in package.get_names(false) { + abandoned_removed_versions + .entry(package_name) + .or_default() + .insert( + package.get_version().to_string(), + package.get_pretty_version().to_string(), + ); + } + continue; + } + + let matching_advisories = self.get_matching_advisories(package.clone(), &advisory_map); + if matching_advisories.len() > 0 { + for package_name in package.get_names(false) { + security_removed_versions + .entry(package_name) + .or_default() + .insert( + package.get_version().to_string(), + matching_advisories.clone(), + ); + } + + continue; + } + + packages.push(package.clone()); + } + + Ok(Pool::new( + packages, + pool.get_unacceptable_fixed_or_locked_packages().clone(), + pool.get_all_removed_versions().clone(), + pool.get_all_removed_versions_by_package().clone(), + security_removed_versions, + abandoned_removed_versions, + )) } - /// @param array<string, array<PartialSecurityAdvisory|SecurityAdvisory>> $advisoryMap - /// @return list<PartialSecurityAdvisory|SecurityAdvisory> fn get_matching_advisories( &self, package: BasePackageHandle, - advisory_map: &IndexMap<String, Vec<PartialSecurityAdvisory>>, - ) -> Vec<PartialSecurityAdvisory> { + advisory_map: &IndexMap<String, Vec<PartialOrFullSecurityAdvisory>>, + ) -> Vec<PartialOrFullSecurityAdvisory> { if package.is_dev() { return vec![]; } - let mut matching_advisories: Vec<PartialSecurityAdvisory> = vec![]; + let mut matching_advisories: Vec<PartialOrFullSecurityAdvisory> = vec![]; for package_name in package.get_names(false) { if !advisory_map.contains_key(&package_name) { continue; @@ -67,10 +160,8 @@ impl SecurityAdvisoryPoolFilter { SimpleConstraint::new("==".to_string(), package.get_version().to_string(), None) .into(); for advisory in &advisory_map[&package_name] { - // advisory is PartialSecurityAdvisory or SecurityAdvisory; both have affected_versions: Box<dyn ConstraintInterface> - if advisory.affected_versions.matches(&package_constraint) { - // TODO(phase-b): PartialSecurityAdvisory is not Clone; replace with Rc when sharing is needed - matching_advisories.push(todo!("clone PartialSecurityAdvisory")); + if advisory.affected_versions().matches(&package_constraint) { + matching_advisories.push(advisory.clone()); } } } |
