Skip to content

Commit

Permalink
Implement recursive option
Browse files Browse the repository at this point in the history
Closes #16
  • Loading branch information
ilpianista committed Mar 3, 2020
1 parent 293d6ab commit 73899fe
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 7 deletions.
2 changes: 1 addition & 1 deletion completions/zsh/_arch-audit
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ _arguments -s -S \
"(-V --version)"{-V,--version}"[Prints version information]" \
"(-b --dbpath)"{-b,--dbpath}"[Set an alternate database location]:dbpath:_files -/" \
"(-C --color)"{-C,--color}"[Colorize the output]:color:(never always auto)" \
"(-f --format)"{-f,--format}"[Specify a format to control the output. Placeholders are %n (pkgname), %c (CVEs) and %v (fixed version)]:format" \
"(-f --format)"{-f,--format}"[Specify a format to control the output. Placeholders are %n (pkgname), %c (CVEs), %v (fixed version) and %r (required by)]:format" \
&& return 0
6 changes: 5 additions & 1 deletion doc/arch-audit.1
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ Specify a format to control the output. Placeholders are
.B %c
(CVEs) and
.B %v
(fixed version).
(fixed version) and
.B %r
(required by) which is only evaluated when
.B --recursive
is also set.
.RE
.SH "AUTHOR"
Developer: Andrea Scarpino <andrea@archlinux.org>
2 changes: 2 additions & 0 deletions src/avg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub struct AVG {
pub fixed: Option<String>,
pub severity: Severity,
pub status: Status,
pub required_by: Vec<String>,
}

impl Default for AVG {
Expand All @@ -15,6 +16,7 @@ impl Default for AVG {
fixed: None,
severity: Severity::Unknown,
status: Status::Unknown,
required_by: vec![],
}
}
}
7 changes: 6 additions & 1 deletion src/cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@ args:
short: f
long: format
takes_value: true
help: Specify a format to control the output. Placeholders are %n (pkgname), %c (CVEs) and %v (fixed version)
help: Specify a format to control the output. Placeholders are %n (pkgname), %c (CVEs), %v (fixed version) and %r (required by, only when -r is also used).
- quiet:
short: q
long: quiet
multiple: true
help: Show only vulnerable package names and their versions. Set twice to hide more.
- recursive:
short: r
long: recursive
multiple: true
help: Prints packages that depend on vulnerable packages and are thus potentially vulnerable as well. Set twice to show the packages that require them as well. Set three times to show ALL the packages that requires them.
- testing:
short: t
long: show-testing
Expand Down
65 changes: 61 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct Options {
color: enums::Color,
format: Option<String>,
quiet: u64,
recursive: u64,
upgradable_only: bool,
show_testing: bool,
}
Expand Down Expand Up @@ -51,6 +52,7 @@ fn main() {
}
},
quiet: args.occurrences_of("quiet"),
recursive: args.occurrences_of("recursive"),
upgradable_only: args.is_present("upgradable"),
show_testing: args.is_present("testing"),
};
Expand Down Expand Up @@ -136,10 +138,27 @@ fn main() {
}
}

let merged = merge_avgs(&affected_avgs);
let merged = merge_avgs(&affected_avgs, &db, &options);
print_avgs(&options, &merged);
}

fn get_required_by(db: &alpm::Db, packages: &[String]) -> Vec<String> {
let mut required_by = vec![];

for pkg in packages {
required_by.append(
&mut db
.pkg(pkg)
.unwrap()
.required_by()
.map(|r| r)
.collect::<Vec<_>>(),
);
}

required_by
}

/// Converts a JSON to an `avg::AVG`
fn to_avg(data: &Value) -> avg::AVG {
avg::AVG {
Expand All @@ -165,6 +184,7 @@ fn to_avg(data: &Value) -> avg::AVG {
.to_string()
.parse::<enums::Status>()
.expect("parse::<Status> failed"),
required_by: vec![],
}
}

Expand Down Expand Up @@ -231,6 +251,7 @@ fn test_system_is_affected() {
fixed: Some("1.0.0".to_string()),
severity: enums::Severity::Unknown,
status: enums::Status::Unknown,
required_by: vec![],
};

assert_eq!(false, system_is_affected(&db, &"pacman".to_string(), &avg1));
Expand All @@ -240,6 +261,7 @@ fn test_system_is_affected() {
fixed: Some("7.0.0".to_string()),
severity: enums::Severity::Unknown,
status: enums::Status::Unknown,
required_by: vec![],
};

assert!(system_is_affected(&db, &"pacman".to_string(), &avg2));
Expand Down Expand Up @@ -272,7 +294,11 @@ fn test_package_is_installed() {
}

/// Merge a list of `avg::AVG` into a single `avg::AVG` using major version as version
fn merge_avgs(cves: &BTreeMap<String, Vec<avg::AVG>>) -> BTreeMap<String, avg::AVG> {
fn merge_avgs(
cves: &BTreeMap<String, Vec<avg::AVG>>,
db: &alpm::Db,
options: &Options,
) -> BTreeMap<String, avg::AVG> {
let mut avgs: BTreeMap<String, avg::AVG> = BTreeMap::new();
for (pkg, list) in cves.iter() {
let mut avg_issues = vec![];
Expand Down Expand Up @@ -304,12 +330,28 @@ fn merge_avgs(cves: &BTreeMap<String, Vec<avg::AVG>>) -> BTreeMap<String, avg::A
}
}

let avg = avg::AVG {
let mut avg = avg::AVG {
issues: avg_issues,
fixed: avg_fixed,
severity: avg_severity,
status: avg_status,
required_by: vec![],
};

if options.recursive >= 1 {
let mut packages = get_required_by(&db, &[pkg.clone()]);
avg.required_by.append(&mut packages.clone());

loop {
if !packages.is_empty() && options.recursive > 1 {
packages = get_required_by(&db, &packages);
avg.required_by.append(&mut packages.clone());
} else {
break;
}
}
}

avgs.insert(pkg.to_string(), avg);
}

Expand All @@ -325,13 +367,15 @@ fn test_merge_avgs() {
fixed: Some("1.0.0".to_string()),
severity: enums::Severity::Unknown,
status: enums::Status::Fixed,
required_by: vec![],
};

let avg2 = avg::AVG {
issues: vec!["CVE-4".to_string(), "CVE-10".to_string()],
fixed: Some("0.9.8".to_string()),
severity: enums::Severity::High,
status: enums::Status::Testing,
required_by: vec![],
};

assert!(enums::Severity::Critical > enums::Severity::High);
Expand All @@ -340,7 +384,10 @@ fn test_merge_avgs() {

avgs.insert("package2".to_string(), vec![avg1, avg2]);

let merged = merge_avgs(&avgs);
let pacman = alpm::Alpm::new(ROOT_DIR, DB_PATH).expect("Alpm::new failed");
let db = pacman.localdb();

let merged = merge_avgs(&avgs, &db, &Options::default());

assert_eq!(2, merged.len());
assert_eq!(
Expand Down Expand Up @@ -435,6 +482,11 @@ fn print_avg_colored(
write_with_colours(t, pkg, options, None, Some(term::Attr::Bold));
// Normal "is affected by {issues}"
write!(t, " is affected by {}. ", avg.issues.join(", ")).expect("term::write failed");

if !avg.required_by.is_empty() {
write!(t, "It's required by {}. ", avg.required_by.join(", ")).expect("term::write failed");
}

// Colored severit
write_with_colours(
t,
Expand Down Expand Up @@ -495,6 +547,11 @@ fn print_avg_formatted(
.expect("term::write failed");
chars.next();
}
Some('r') => {
write!(t, "{}", avg.required_by.iter().join(",").as_str())
.expect("term::write failed");
chars.next();
}
Some('v') => {
if !version.is_empty()
&& (avg.status == Status::Fixed
Expand Down

0 comments on commit 73899fe

Please sign in to comment.