Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: add conversion from layer to markdown
  • Loading branch information
tembleking committed Oct 3, 2025
commit 98692cb90a3e290ac261c18fbe15a487a5654c12
48 changes: 46 additions & 2 deletions src/app/markdown/markdown_fixable_package_table.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use std::fmt::{Display, Formatter};
use std::{
fmt::{Display, Formatter},
sync::Arc,
};

use markdown_table::{Heading, HeadingAlignment, MarkdownTable};

use crate::domain::scanresult::{scan_result::ScanResult, severity::Severity};
use crate::domain::scanresult::{layer::Layer, scan_result::ScanResult, severity::Severity};

#[derive(Clone, Debug, Default)]
pub struct FixablePackage {
Expand Down Expand Up @@ -67,6 +70,47 @@ impl From<&ScanResult> for FixablePackageTable {
}
}

impl From<&Arc<Layer>> for FixablePackageTable {
fn from(value: &Arc<Layer>) -> Self {
FixablePackageTable(
value
.packages()
.into_iter()
.filter(|p| p.vulnerabilities().iter().any(|v| v.fixable()))
.map(|p| {
let mut vulns = FixablePackageVulnerabilities::default();
let mut exploits = 0;
for v in p.vulnerabilities() {
if v.exploitable() {
exploits += 1;
}
match v.severity() {
Severity::Critical => vulns.critical += 1,
Severity::High => vulns.high += 1,
Severity::Medium => vulns.medium += 1,
Severity::Low => vulns.low += 1,
Severity::Negligible => vulns.negligible += 1,
Severity::Unknown => {}
}
}

FixablePackage {
name: p.name().to_string(),
package_type: p.package_type().to_string(),
version: p.version().to_string(),
suggested_fix: p
.vulnerabilities()
.iter()
.find_map(|v| v.fix_version().map(|s| s.to_string())),
vulnerabilities: vulns,
exploits,
}
})
.collect(),
)
}
}

impl Display for FixablePackageTable {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.0.is_empty() {
Expand Down
38 changes: 38 additions & 0 deletions src/app/markdown/markdown_layer_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::{
fmt::{Display, Formatter},
sync::Arc,
};

use crate::domain::scanresult::layer::Layer;

use super::{
markdown_fixable_package_table::FixablePackageTable,
markdown_vulnerability_evaluated_table::VulnerabilityEvaluatedTable,
};

pub struct MarkdownLayerData {
pub fixable_packages: FixablePackageTable,
pub vulnerabilities: VulnerabilityEvaluatedTable,
}

impl From<Arc<Layer>> for MarkdownLayerData {
fn from(value: Arc<Layer>) -> Self {
Self {
fixable_packages: FixablePackageTable::from(&value),
vulnerabilities: VulnerabilityEvaluatedTable::from(&value),
}
}
}

impl Display for MarkdownLayerData {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let fixable_packages_section = self.fixable_packages.to_string();
let vulnerability_detail_section = self.vulnerabilities.to_string();

write!(
f,
"## Sysdig Scan Result for Layer\n{}\n{}",
fixable_packages_section, vulnerability_detail_section
)
}
}
34 changes: 32 additions & 2 deletions src/app/markdown/markdown_vulnerability_evaluated_table.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::fmt::{Display, Formatter};
use std::{
fmt::{Display, Formatter},
sync::Arc,
};

use itertools::Itertools;
use markdown_table::{Heading, HeadingAlignment, MarkdownTable};

use crate::domain::scanresult::scan_result::ScanResult;
use crate::domain::scanresult::{layer::Layer, scan_result::ScanResult};

#[derive(Clone, Debug, Default)]
pub struct VulnerabilityEvaluated {
Expand Down Expand Up @@ -45,6 +48,33 @@ impl From<&ScanResult> for VulnerabilityEvaluatedTable {
)
}
}
impl From<&Arc<Layer>> for VulnerabilityEvaluatedTable {
fn from(value: &Arc<Layer>) -> Self {
VulnerabilityEvaluatedTable(
value
.vulnerabilities()
.iter()
.sorted_by_key(|v| v.cve())
.sorted_by(|a, b| {
b.found_in_packages()
.len()
.cmp(&a.found_in_packages().len())
})
.sorted_by(|a, b| b.fixable().cmp(&a.fixable()))
.sorted_by(|a, b| b.exploitable().cmp(&a.exploitable()))
.sorted_by_key(|v| v.severity())
.map(|v| VulnerabilityEvaluated {
cve: v.cve().to_string(),
severity: v.severity().to_string(),
packages_found: v.found_in_packages().len() as u32,
fixable: v.fixable(),
exploitable: v.exploitable(),
accepted_risk: !v.accepted_risks().is_empty(),
})
.collect(),
)
}
}

impl Display for VulnerabilityEvaluatedTable {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Expand Down
1 change: 1 addition & 0 deletions src/app/markdown/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod markdown_data;
mod markdown_fixable_package_table;
mod markdown_layer_data;
mod markdown_policy_evaluated_table;
mod markdown_summary;
mod markdown_summary_table;
Expand Down